Merge changes I6e3f4da2,I8acfbd1a into nyc-dev

* changes:
  Fully detach unused scrap views
  Remove detached headers
This commit is contained in:
Yigit Boyar
2016-05-11 22:32:04 +00:00
committed by Android (Google) Code Review
2 changed files with 74 additions and 10 deletions

View File

@@ -2322,7 +2322,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*
* @param position The position to display
* @param isScrap Array of at least 1 boolean, the first entry will become true if
* the returned view was taken from the scrap heap, false if otherwise.
* the returned view was taken from the "temporary detached" scrap heap, false if
* otherwise.
*
* @return A view displaying the data associated with the specified position
*/
@@ -2362,10 +2363,18 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// Failed to re-bind the data, return scrap to the heap.
mRecycler.addScrapView(scrapView, position);
} else {
isScrap[0] = true;
if (child.isTemporarilyDetached()) {
isScrap[0] = true;
// Finish the temporary detach started in addScrapView().
child.dispatchFinishTemporaryDetach();
} else {
// we set isScrap to "true" only if the view is temporarily detached.
// if the view is fully detached, it is as good as a view created by the
// adapter
isScrap[0] = false;
}
// Finish the temporary detach started in addScrapView().
child.dispatchFinishTemporaryDetach();
}
}
@@ -5152,6 +5161,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
fillGap(down);
}
mRecycler.fullyDetachScrapViews();
if (!inTouchMode && mSelectedPosition != INVALID_POSITION) {
final int childIndex = mSelectedPosition - mFirstPosition;
if (childIndex >= 0 && childIndex < getChildCount()) {
@@ -6861,8 +6871,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
scrapViews = mScrapViews[whichScrap];
}
victim.dispatchStartTemporaryDetach();
lp.scrappedFromPosition = mFirstActivePosition + i;
removeDetachedView(victim, false);
scrapViews.add(victim);
if (hasListener) {
@@ -6871,10 +6881,28 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
}
pruneScrapViews();
}
/**
* At the end of a layout pass, all temp detached views should either be re-attached or
* completely detached. This method ensures that any remaining view in the scrap list is
* fully detached.
*/
void fullyDetachScrapViews() {
final int viewTypeCount = mViewTypeCount;
final ArrayList<View>[] scrapViews = mScrapViews;
for (int i = 0; i < viewTypeCount; ++i) {
final ArrayList<View> scrapPile = scrapViews[i];
for (int j = scrapPile.size() - 1; j >= 0; j--) {
final View view = scrapPile.get(j);
if (view.isTemporarilyDetached()) {
removeDetachedView(view, false);
}
}
}
}
/**
* Makes sure that the size of mScrapViews does not exceed the size of
* mActiveViews, which can happen if an adapter does not recycle its
@@ -6888,10 +6916,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
for (int i = 0; i < viewTypeCount; ++i) {
final ArrayList<View> scrapPile = scrapViews[i];
int size = scrapPile.size();
final int extras = size - maxViews;
size--;
for (int j = 0; j < extras; j++) {
removeDetachedView(scrapPile.remove(size--), false);
while (size > maxViews) {
scrapPile.remove(--size);
}
}

View File

@@ -54,6 +54,7 @@ import android.view.accessibility.AccessibilityNodeProvider;
import android.widget.RemoteViews.RemoteView;
import java.util.ArrayList;
import java.util.List;
/*
* Implementation Notes:
@@ -1763,6 +1764,10 @@ public class ListView extends AbsListView {
// Flush any cached views that did not get reused above
recycleBin.scrapActiveViews();
// remove any header/footer that has been temp detached and not re-attached
removeUnusedFixedViews(mHeaderViewInfos);
removeUnusedFixedViews(mFooterViewInfos);
if (sel != null) {
// The current selected item should get focus if items are
// focusable.
@@ -1879,6 +1884,36 @@ public class ListView extends AbsListView {
}
}
@Override
boolean trackMotionScroll(int deltaY, int incrementalDeltaY) {
final boolean result = super.trackMotionScroll(deltaY, incrementalDeltaY);
removeUnusedFixedViews(mHeaderViewInfos);
removeUnusedFixedViews(mFooterViewInfos);
return result;
}
/**
* Header and Footer views are not scrapped / recycled like other views but they are still
* detached from the ViewGroup. After a layout operation, call this method to remove such views.
*
* @param infoList The info list to be traversed
*/
private void removeUnusedFixedViews(@Nullable List<FixedViewInfo> infoList) {
if (infoList == null) {
return;
}
for (int i = infoList.size() - 1; i >= 0; i--) {
final FixedViewInfo fixedViewInfo = infoList.get(i);
final View view = fixedViewInfo.view;
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
if (view.getParent() == null && lp != null && lp.recycledHeaderFooter) {
removeDetachedView(view, false);
lp.recycledHeaderFooter = false;
}
}
}
/**
* @param child a direct child of this list.
* @return Whether child is a header or footer view.
@@ -3179,6 +3214,9 @@ public class ListView extends AbsListView {
last = getChildAt(--lastIndex);
}
}
recycleBin.fullyDetachScrapViews();
removeUnusedFixedViews(mHeaderViewInfos);
removeUnusedFixedViews(mFooterViewInfos);
}
private View addViewAbove(View theView, int position) {