Added descriptions for and renamed fields and methods related to deferring or ignoring nested calls
to requestLayout. I personally found that the names and lack of descriptions made it hard to follow
the logic and meaning of the code.
Bug: None.
Test: None.
Change-Id: I5ee8db3b94bb1e9a41e53add3aa58dfc81a95bda
diff --git a/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
index 4a65553..a287979 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
@@ -350,7 +350,7 @@
return;
}
if (mLayoutFrozen) {
- mLayoutRequestEaten = true;
+ mLayoutWasDefered = true;
return; //we'll process updates when ice age ends.
}
consumePendingUpdateOperations();
@@ -372,10 +372,21 @@
boolean mEnableFastScroller;
@VisibleForTesting boolean mFirstLayoutComplete;
- // Counting lock to control whether we should ignore requestLayout calls from children or not.
- private int mEatRequestLayout = 0;
+ /**
+ * The current depth of nested calls to {@link #startInterceptRequestLayout()} (number of
+ * calls to {@link #startInterceptRequestLayout()} - number of calls to
+ * {@link #stopInterceptRequestLayout(boolean)} . This is used to signal whether we
+ * should defer layout operations caused by layout requests from children of
+ * {@link RecyclerView}.
+ */
+ private int mInterceptRequestLayoutDepth = 0;
- boolean mLayoutRequestEaten;
+ /**
+ * True if a call to requestLayout was intercepted and prevented from executing like normal and
+ * we plan on continuing with normal execution later.
+ */
+ boolean mLayoutWasDefered;
+
boolean mLayoutFrozen;
private boolean mIgnoreMotionEventTillDown;
@@ -1356,7 +1367,7 @@
* @return true if an animating view is removed
*/
boolean removeAnimatingView(View view) {
- eatRequestLayout();
+ startInterceptRequestLayout();
final boolean removed = mChildHelper.removeViewIfHidden(view);
if (removed) {
final ViewHolder viewHolder = getChildViewHolderInt(view);
@@ -1367,7 +1378,7 @@
}
}
// only clear request eaten flag if we removed the view.
- resumeRequestLayout(!removed);
+ stopInterceptRequestLayout(!removed);
return removed;
}
@@ -1737,10 +1748,10 @@
.hasAnyUpdateTypes(AdapterHelper.UpdateOp.ADD | AdapterHelper.UpdateOp.REMOVE
| AdapterHelper.UpdateOp.MOVE)) {
TraceCompat.beginSection(TRACE_HANDLE_ADAPTER_UPDATES_TAG);
- eatRequestLayout();
+ startInterceptRequestLayout();
onEnterLayoutOrScroll();
mAdapterHelper.preProcess();
- if (!mLayoutRequestEaten) {
+ if (!mLayoutWasDefered) {
if (hasUpdatedView()) {
dispatchLayout();
} else {
@@ -1748,7 +1759,7 @@
mAdapterHelper.consumePostponedUpdates();
}
}
- resumeRequestLayout(true);
+ stopInterceptRequestLayout(true);
onExitLayoutOrScroll();
TraceCompat.endSection();
} else if (mAdapterHelper.hasPendingUpdates()) {
@@ -1792,7 +1803,7 @@
consumePendingUpdateOperations();
if (mAdapter != null) {
- eatRequestLayout();
+ startInterceptRequestLayout();
onEnterLayoutOrScroll();
TraceCompat.beginSection(TRACE_SCROLL_TAG);
fillRemainingScrollValues(mState);
@@ -1807,7 +1818,7 @@
TraceCompat.endSection();
repositionShadowingViews();
onExitLayoutOrScroll();
- resumeRequestLayout(false);
+ stopInterceptRequestLayout(false);
}
if (!mItemDecorations.isEmpty()) {
invalidate();
@@ -1984,22 +1995,43 @@
return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollRange(mState) : 0;
}
-
- void eatRequestLayout() {
- mEatRequestLayout++;
- if (mEatRequestLayout == 1 && !mLayoutFrozen) {
- mLayoutRequestEaten = false;
+ /**
+ * This method should be called before any code that may trigger a child view to cause a call to
+ * {@link RecyclerView#requestLayout()}. Doing so enables {@link RecyclerView} to avoid
+ * reacting to additional redundant calls to {@link #requestLayout()}.
+ * <p>
+ * A call to this method must always be accompanied by a call to
+ * {@link #stopInterceptRequestLayout(boolean)} that follows the code that may trigger a
+ * child View to cause a call to {@link RecyclerView#requestLayout()}.
+ *
+ * @see #stopInterceptRequestLayout(boolean)
+ */
+ void startInterceptRequestLayout() {
+ mInterceptRequestLayoutDepth++;
+ if (mInterceptRequestLayoutDepth == 1 && !mLayoutFrozen) {
+ mLayoutWasDefered = false;
}
}
- void resumeRequestLayout(boolean performLayoutChildren) {
- if (mEatRequestLayout < 1) {
+ /**
+ * This method should be called after any code that may trigger a child view to cause a call to
+ * {@link RecyclerView#requestLayout()}.
+ * <p>
+ * A call to this method must always be accompanied by a call to
+ * {@link #startInterceptRequestLayout()} that precedes the code that may trigger a child
+ * View to cause a call to {@link RecyclerView#requestLayout()}.
+ *
+ * @see #startInterceptRequestLayout()
+ */
+ void stopInterceptRequestLayout(boolean performLayoutChildren) {
+ if (mInterceptRequestLayoutDepth < 1) {
//noinspection PointlessBooleanExpression
if (DEBUG) {
- throw new IllegalStateException("invalid eat request layout count"
+ throw new IllegalStateException("stopInterceptRequestLayout was called more "
+ + "times than startInterceptRequestLayout."
+ exceptionLabel());
}
- mEatRequestLayout = 1;
+ mInterceptRequestLayoutDepth = 1;
}
if (!performLayoutChildren && !mLayoutFrozen) {
// Reset the layout request eaten counter.
@@ -2010,19 +2042,19 @@
// eat layout for dispatchLayout
// a bunch of req layout calls arrive
- mLayoutRequestEaten = false;
+ mLayoutWasDefered = false;
}
- if (mEatRequestLayout == 1) {
+ if (mInterceptRequestLayoutDepth == 1) {
// when layout is frozen we should delay dispatchLayout()
- if (performLayoutChildren && mLayoutRequestEaten && !mLayoutFrozen
+ if (performLayoutChildren && mLayoutWasDefered && !mLayoutFrozen
&& mLayout != null && mAdapter != null) {
dispatchLayout();
}
if (!mLayoutFrozen) {
- mLayoutRequestEaten = false;
+ mLayoutWasDefered = false;
}
}
- mEatRequestLayout--;
+ mInterceptRequestLayoutDepth--;
}
/**
@@ -2052,10 +2084,10 @@
assertNotInLayoutOrScroll("Do not setLayoutFrozen in layout or scroll");
if (!frozen) {
mLayoutFrozen = false;
- if (mLayoutRequestEaten && mLayout != null && mAdapter != null) {
+ if (mLayoutWasDefered && mLayout != null && mAdapter != null) {
requestLayout();
}
- mLayoutRequestEaten = false;
+ mLayoutWasDefered = false;
} else {
final long now = SystemClock.uptimeMillis();
MotionEvent cancelEvent = MotionEvent.obtain(now, now,
@@ -2472,9 +2504,9 @@
// panic, focused view is not a child anymore, cannot call super.
return null;
}
- eatRequestLayout();
+ startInterceptRequestLayout();
mLayout.onFocusSearchFailed(focused, direction, mRecycler, mState);
- resumeRequestLayout(false);
+ stopInterceptRequestLayout(false);
}
result = ff.findNextFocus(this, focused, direction);
} else {
@@ -2486,9 +2518,9 @@
// panic, focused view is not a child anymore, cannot call super.
return null;
}
- eatRequestLayout();
+ startInterceptRequestLayout();
result = mLayout.onFocusSearchFailed(focused, direction, mRecycler, mState);
- resumeRequestLayout(false);
+ stopInterceptRequestLayout(false);
}
}
if (result != null && !result.hasFocusable()) {
@@ -3203,7 +3235,7 @@
}
// custom onMeasure
if (mAdapterUpdateDuringMeasure) {
- eatRequestLayout();
+ startInterceptRequestLayout();
onEnterLayoutOrScroll();
processAdapterUpdatesAndSetAnimationFlags();
onExitLayoutOrScroll();
@@ -3216,7 +3248,7 @@
mState.mInPreLayout = false;
}
mAdapterUpdateDuringMeasure = false;
- resumeRequestLayout(false);
+ stopInterceptRequestLayout(false);
} else if (mState.mRunPredictiveAnimations) {
// If mAdapterUpdateDuringMeasure is false and mRunPredictiveAnimations is true:
// this means there is already an onMeasure() call performed to handle the pending
@@ -3232,9 +3264,9 @@
} else {
mState.mItemCount = 0;
}
- eatRequestLayout();
+ startInterceptRequestLayout();
mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
- resumeRequestLayout(false);
+ stopInterceptRequestLayout(false);
mState.mInPreLayout = false; // clear
}
}
@@ -3669,7 +3701,7 @@
mState.assertLayoutStep(State.STEP_START);
fillRemainingScrollValues(mState);
mState.mIsMeasuring = false;
- eatRequestLayout();
+ startInterceptRequestLayout();
mViewInfoStore.clear();
onEnterLayoutOrScroll();
processAdapterUpdatesAndSetAnimationFlags();
@@ -3749,7 +3781,7 @@
clearOldPositions();
}
onExitLayoutOrScroll();
- resumeRequestLayout(false);
+ stopInterceptRequestLayout(false);
mState.mLayoutStep = State.STEP_LAYOUT;
}
@@ -3758,7 +3790,7 @@
* This step might be run multiple times if necessary (e.g. measure).
*/
private void dispatchLayoutStep2() {
- eatRequestLayout();
+ startInterceptRequestLayout();
onEnterLayoutOrScroll();
mState.assertLayoutStep(State.STEP_LAYOUT | State.STEP_ANIMATIONS);
mAdapterHelper.consumeUpdatesInOnePass();
@@ -3776,7 +3808,7 @@
mState.mRunSimpleAnimations = mState.mRunSimpleAnimations && mItemAnimator != null;
mState.mLayoutStep = State.STEP_ANIMATIONS;
onExitLayoutOrScroll();
- resumeRequestLayout(false);
+ stopInterceptRequestLayout(false);
}
/**
@@ -3785,7 +3817,7 @@
*/
private void dispatchLayoutStep3() {
mState.assertLayoutStep(State.STEP_ANIMATIONS);
- eatRequestLayout();
+ startInterceptRequestLayout();
onEnterLayoutOrScroll();
mState.mLayoutStep = State.STEP_START;
if (mState.mRunSimpleAnimations) {
@@ -3861,7 +3893,7 @@
mLayout.onLayoutCompleted(mState);
onExitLayoutOrScroll();
- resumeRequestLayout(false);
+ stopInterceptRequestLayout(false);
mViewInfoStore.clear();
if (didChildRangeChange(mMinMaxLayoutPositions[0], mMinMaxLayoutPositions[1])) {
dispatchOnScrolled(0, 0);
@@ -4044,10 +4076,10 @@
@Override
public void requestLayout() {
- if (mEatRequestLayout == 0 && !mLayoutFrozen) {
+ if (mInterceptRequestLayoutDepth == 0 && !mLayoutFrozen) {
super.requestLayout();
} else {
- mLayoutRequestEaten = true;
+ mLayoutWasDefered = true;
}
}
@@ -4906,7 +4938,7 @@
}
if (mAdapter != null) {
- eatRequestLayout();
+ startInterceptRequestLayout();
onEnterLayoutOrScroll();
TraceCompat.beginSection(TRACE_SCROLL_TAG);
fillRemainingScrollValues(mState);
@@ -4922,7 +4954,7 @@
repositionShadowingViews();
onExitLayoutOrScroll();
- resumeRequestLayout(false);
+ stopInterceptRequestLayout(false);
if (smoothScroller != null && !smoothScroller.isPendingInitialRun()
&& smoothScroller.isRunning()) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
index dbad400..602fd56 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
@@ -2474,7 +2474,7 @@
assertThat(hidden, CoreMatchers.notNullValue());
assertThat(updated, CoreMatchers.notNullValue());
- mRecyclerView.eatRequestLayout();
+ mRecyclerView.startInterceptRequestLayout();
// first put the hidden child back
int index1 = mRecyclerView.indexOfChild(hidden.itemView);