Merge "DO NOT MERGE Ensure transient state views are temporarily detached" into klp-dev

This commit is contained in:
Alan Viverette
2014-03-11 02:11:58 +00:00
committed by Android (Google) Code Review

View File

@@ -2228,26 +2228,28 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "obtainView"); Trace.traceBegin(Trace.TRACE_TAG_VIEW, "obtainView");
isScrap[0] = false; isScrap[0] = false;
View scrapView;
scrapView = mRecycler.getTransientStateView(position); // Check whether we have a transient state view. Attempt to re-bind the
if (scrapView == null) { // data and discard the view if we fail.
scrapView = mRecycler.getScrapView(position); final View transientView = mRecycler.getTransientStateView(position);
} if (transientView != null) {
final View updatedView = mAdapter.getView(position, transientView, this);
View child; if (updatedView != transientView) {
if (scrapView != null) { // Failed to re-bind the data, scrap the obtained view.
child = mAdapter.getView(position, scrapView, this); mRecycler.addScrapView(updatedView, position);
if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
} }
// Scrap view implies temporary detachment.
isScrap[0] = true;
return transientView;
}
final View scrapView = mRecycler.getScrapView(position);
final View child = mAdapter.getView(position, scrapView, this);
if (scrapView != null) {
if (child != scrapView) { if (child != scrapView) {
// Failed to re-bind the data, return scrap to the heap.
mRecycler.addScrapView(scrapView, position); mRecycler.addScrapView(scrapView, position);
if (mCacheColorHint != 0) {
child.setDrawingCacheBackgroundColor(mCacheColorHint);
}
} else { } else {
isScrap[0] = true; isScrap[0] = true;
@@ -2259,16 +2261,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
child.dispatchFinishTemporaryDetach(); child.dispatchFinishTemporaryDetach();
} }
} else { }
child = mAdapter.getView(position, null, this);
if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { if (mCacheColorHint != 0) {
child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); child.setDrawingCacheBackgroundColor(mCacheColorHint);
} }
if (mCacheColorHint != 0) { if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
child.setDrawingCacheBackgroundColor(mCacheColorHint); child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
}
} }
if (mAdapterHasStableIds) { if (mAdapterHasStableIds) {
@@ -6562,12 +6562,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
} }
} }
if (mTransientStateViews != null) {
mTransientStateViews.clear(); clearTransientStateViews();
}
if (mTransientStateViewsById != null) {
mTransientStateViewsById.clear();
}
} }
/** /**
@@ -6634,14 +6630,26 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
/** /**
* Dump any currently saved views with transient state. * Dumps and fully detaches any currently saved views with transient
* state.
*/ */
void clearTransientStateViews() { void clearTransientStateViews() {
if (mTransientStateViews != null) { final SparseArray<View> viewsByPos = mTransientStateViews;
mTransientStateViews.clear(); if (viewsByPos != null) {
final int N = viewsByPos.size();
for (int i = 0; i < N; i++) {
removeDetachedView(viewsByPos.valueAt(i), false);
}
viewsByPos.clear();
} }
if (mTransientStateViewsById != null) {
mTransientStateViewsById.clear(); final LongSparseArray<View> viewsById = mTransientStateViewsById;
if (viewsById != null) {
final int N = viewsById.size();
for (int i = 0; i < N; i++) {
removeDetachedView(viewsById.valueAt(i), false);
}
viewsById.clear();
} }
} }
@@ -6766,44 +6774,48 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (victim != null) { if (victim != null) {
final AbsListView.LayoutParams lp final AbsListView.LayoutParams lp
= (AbsListView.LayoutParams) victim.getLayoutParams(); = (AbsListView.LayoutParams) victim.getLayoutParams();
int whichScrap = lp.viewType; final int whichScrap = lp.viewType;
activeViews[i] = null; activeViews[i] = null;
final boolean scrapHasTransientState = victim.hasTransientState(); if (victim.hasTransientState()) {
if (!shouldRecycleViewType(whichScrap) || scrapHasTransientState) { // Store views with transient state for later use.
// Do not move views that should be ignored victim.dispatchStartTemporaryDetach();
if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER &&
scrapHasTransientState) { if (mAdapter != null && mAdapterHasStableIds) {
if (mTransientStateViewsById == null) {
mTransientStateViewsById = new LongSparseArray<View>();
}
long id = mAdapter.getItemId(mFirstActivePosition + i);
mTransientStateViewsById.put(id, victim);
} else if (!mDataChanged) {
if (mTransientStateViews == null) {
mTransientStateViews = new SparseArray<View>();
}
mTransientStateViews.put(mFirstActivePosition + i, victim);
} else if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
// The data has changed, we can't keep this view.
removeDetachedView(victim, false); removeDetachedView(victim, false);
} }
if (scrapHasTransientState) { } else if (!shouldRecycleViewType(whichScrap)) {
if (mAdapter != null && mAdapterHasStableIds) { // Discard non-recyclable views except headers/footers.
if (mTransientStateViewsById == null) { if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
mTransientStateViewsById = new LongSparseArray<View>(); removeDetachedView(victim, false);
} }
long id = mAdapter.getItemId(mFirstActivePosition + i); } else {
mTransientStateViewsById.put(id, victim); // Store everything else on the appropriate scrap heap.
} else { if (multipleScraps) {
if (mTransientStateViews == null) { scrapViews = mScrapViews[whichScrap];
mTransientStateViews = new SparseArray<View>();
}
mTransientStateViews.put(mFirstActivePosition + i, victim);
}
} }
continue;
}
if (multipleScraps) { victim.dispatchStartTemporaryDetach();
scrapViews = mScrapViews[whichScrap]; lp.scrappedFromPosition = mFirstActivePosition + i;
} scrapViews.add(victim);
victim.dispatchStartTemporaryDetach();
lp.scrappedFromPosition = mFirstActivePosition + i;
scrapViews.add(victim);
victim.setAccessibilityDelegate(null); victim.setAccessibilityDelegate(null);
if (hasListener) { if (hasListener) {
mRecyclerListener.onMovedToScrapHeap(victim); mRecyclerListener.onMovedToScrapHeap(victim);
}
} }
} }
} }
@@ -6812,8 +6824,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
/** /**
* Makes sure that the size of mScrapViews does not exceed the size of mActiveViews. * Makes sure that the size of mScrapViews does not exceed the size of
* (This can happen if an adapter does not recycle its views). * mActiveViews, which can happen if an adapter does not recycle its
* views. Removes cached transient state views that no longer have
* transient state.
*/ */
private void pruneScrapViews() { private void pruneScrapViews() {
final int maxViews = mActiveViews.length; final int maxViews = mActiveViews.length;
@@ -6829,20 +6843,25 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
} }
if (mTransientStateViews != null) { final SparseArray<View> transViewsByPos = mTransientStateViews;
for (int i = 0; i < mTransientStateViews.size(); i++) { if (transViewsByPos != null) {
final View v = mTransientStateViews.valueAt(i); for (int i = 0; i < transViewsByPos.size(); i++) {
final View v = transViewsByPos.valueAt(i);
if (!v.hasTransientState()) { if (!v.hasTransientState()) {
mTransientStateViews.removeAt(i); removeDetachedView(v, false);
transViewsByPos.removeAt(i);
i--; i--;
} }
} }
} }
if (mTransientStateViewsById != null) {
for (int i = 0; i < mTransientStateViewsById.size(); i++) { final LongSparseArray<View> transViewsById = mTransientStateViewsById;
final View v = mTransientStateViewsById.valueAt(i); if (transViewsById != null) {
for (int i = 0; i < transViewsById.size(); i++) {
final View v = transViewsById.valueAt(i);
if (!v.hasTransientState()) { if (!v.hasTransientState()) {
mTransientStateViewsById.removeAt(i); removeDetachedView(v, false);
transViewsById.removeAt(i);
i--; i--;
} }
} }