diff options
author | Romain Guy <romainguy@google.com> | 2012-03-14 16:41:42 -0700 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2012-03-14 17:19:35 -0700 |
commit | 9d849a2f6351caed83105b90cab79223ec2bfbd3 (patch) | |
tree | d0569276780cb4cd8123d139deb7dbfa5cbd66b3 /core/java/android/widget | |
parent | 390f882f8905e8d1ac0d4b7f2e01aa04dccc3c16 (diff) | |
download | frameworks_base-9d849a2f6351caed83105b90cab79223ec2bfbd3.zip frameworks_base-9d849a2f6351caed83105b90cab79223ec2bfbd3.tar.gz frameworks_base-9d849a2f6351caed83105b90cab79223ec2bfbd3.tar.bz2 |
Optimize invalidate calls in lists.
AbsListView was doing too many invalidates during scrolls/flings.
Some of them were also covering too large an area of the screen.
Change-Id: I68fe5dda3657bddd673996e7cf4f3c3672c66cfc
Diffstat (limited to 'core/java/android/widget')
-rw-r--r-- | core/java/android/widget/AbsListView.java | 92 | ||||
-rw-r--r-- | core/java/android/widget/EdgeEffect.java | 49 |
2 files changed, 101 insertions, 40 deletions
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 5774440..9e07151 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -88,6 +88,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te ViewTreeObserver.OnTouchModeChangeListener, RemoteViewsAdapter.RemoteAdapterConnectionCallback { + @SuppressWarnings("UnusedDeclaration") private static final String TAG = "AbsListView"; /** @@ -2429,7 +2430,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final ViewTreeObserver treeObserver = getViewTreeObserver(); treeObserver.removeOnTouchModeChangeListener(this); if (mTextFilterEnabled && mPopup != null) { - treeObserver.removeGlobalOnLayoutListener(this); + treeObserver.removeOnGlobalLayoutListener(this); mGlobalLayoutListenerAddedFilter = false; } @@ -2943,11 +2944,23 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mDirection = 0; // Reset when entering overscroll. mTouchMode = TOUCH_MODE_OVERSCROLL; if (rawDeltaY > 0) { + if (!mEdgeGlowTop.isIdle()) { + invalidate(mEdgeGlowTop.getBounds()); + } else { + invalidate(); + } + mEdgeGlowTop.onPull((float) overscroll / getHeight()); if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } } else if (rawDeltaY < 0) { + if (!mEdgeGlowBottom.isIdle()) { + invalidate(mEdgeGlowBottom.getBounds()); + } else { + invalidate(); + } + mEdgeGlowBottom.onPull((float) overscroll / getHeight()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); @@ -2956,7 +2969,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } mMotionY = y; - invalidate(); } mLastY = y; } @@ -2990,26 +3002,26 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (!mEdgeGlowBottom.isFinished()) { mEdgeGlowBottom.onRelease(); } + invalidate(mEdgeGlowTop.getBounds()); } else if (rawDeltaY < 0) { mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight()); if (!mEdgeGlowTop.isFinished()) { mEdgeGlowTop.onRelease(); } + invalidate(mEdgeGlowBottom.getBounds()); } - invalidate(); } } if (incrementalDeltaY != 0) { // Coming back to 'real' list scrolling - mScrollY = 0; - invalidateParentIfNeeded(); - - // No need to do all this work if we're not going to move anyway - if (incrementalDeltaY != 0) { - trackMotionScroll(incrementalDeltaY, incrementalDeltaY); + if (mScrollY != 0) { + mScrollY = 0; + invalidateParentIfNeeded(); } + trackMotionScroll(incrementalDeltaY, incrementalDeltaY); + mTouchMode = TOUCH_MODE_SCROLL; // We did not scroll the full amount. Treat this essentially like the @@ -3468,11 +3480,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int rightPadding = mListPadding.right + mGlowPaddingRight; final int width = getWidth() - leftPadding - rightPadding; - canvas.translate(leftPadding, - Math.min(0, scrollY + mFirstPositionDistanceGuess)); + int edgeY = Math.min(0, scrollY + mFirstPositionDistanceGuess); + canvas.translate(leftPadding, edgeY); mEdgeGlowTop.setSize(width, getHeight()); if (mEdgeGlowTop.draw(canvas)) { - invalidate(); + mEdgeGlowTop.setPosition(leftPadding, edgeY); + invalidate(mEdgeGlowTop.getBounds()); } canvas.restoreToCount(restoreCount); } @@ -3483,12 +3496,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int width = getWidth() - leftPadding - rightPadding; final int height = getHeight(); - canvas.translate(-width + leftPadding, - Math.max(height, scrollY + mLastPositionDistanceGuess)); + int edgeX = -width + leftPadding; + int edgeY = Math.max(height, scrollY + mLastPositionDistanceGuess); + canvas.translate(edgeX, edgeY); canvas.rotate(180, width, 0); mEdgeGlowBottom.setSize(width, height); if (mEdgeGlowBottom.draw(canvas)) { - invalidate(); + // Account for the rotation + mEdgeGlowBottom.setPosition(edgeX + width, edgeY - mEdgeGlowBottom.getHeight()); + invalidate(mEdgeGlowBottom.getBounds()); } canvas.restoreToCount(restoreCount); } @@ -3874,7 +3890,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } // Don't stop just because delta is zero (it could have been rounded) - final boolean atEnd = trackMotionScroll(delta, delta) && (delta != 0); + final boolean atEdge = trackMotionScroll(delta, delta); + final boolean atEnd = atEdge && (delta != 0); if (atEnd) { if (motionView != null) { // Tweak the scroll for how far we overshot @@ -3889,7 +3906,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } if (more && !atEnd) { - invalidate(); + if (atEdge) invalidate(); mLastFlingY = y; post(this); } else { @@ -4431,7 +4448,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } private void createScrollingCache() { - if (mScrollingCacheEnabled && !mCachingStarted) { + if (mScrollingCacheEnabled && !mCachingStarted && !isHardwareAccelerated()) { setChildrenDrawnWithCacheEnabled(true); setChildrenDrawingCacheEnabled(true); mCachingStarted = mCachingActive = true; @@ -4439,23 +4456,25 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } private void clearScrollingCache() { - if (mClearScrollingCache == null) { - mClearScrollingCache = new Runnable() { - public void run() { - if (mCachingStarted) { - mCachingStarted = mCachingActive = false; - setChildrenDrawnWithCacheEnabled(false); - if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) { - setChildrenDrawingCacheEnabled(false); - } - if (!isAlwaysDrawnWithCacheEnabled()) { - invalidate(); + if (!isHardwareAccelerated()) { + if (mClearScrollingCache == null) { + mClearScrollingCache = new Runnable() { + public void run() { + if (mCachingStarted) { + mCachingStarted = mCachingActive = false; + setChildrenDrawnWithCacheEnabled(false); + if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) { + setChildrenDrawingCacheEnabled(false); + } + if (!isAlwaysDrawnWithCacheEnabled()) { + invalidate(); + } } } - } - }; + }; + } + post(mClearScrollingCache); } - post(mClearScrollingCache); } /** @@ -4599,14 +4618,18 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mRecycler.removeSkippedScrap(); } + // invalidate before moving the children to avoid unnecessary invalidate + // calls to bubble up from the children all the way to the top + if (!awakenScrollBars()) { + invalidate(); + } + offsetChildrenTopAndBottom(incrementalDeltaY); if (down) { mFirstPosition += count; } - invalidate(); - final int absIncrementalDeltaY = Math.abs(incrementalDeltaY); if (spaceAbove < absIncrementalDeltaY || spaceBelow < absIncrementalDeltaY) { fillGap(down); @@ -4629,7 +4652,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mBlockLayoutRequests = false; invokeOnItemScrollListener(); - awakenScrollBars(); return false; } diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 83aa8ba..c1f31bb 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -16,6 +16,7 @@ package android.widget; +import android.graphics.Rect; import com.android.internal.R; import android.content.Context; @@ -45,6 +46,7 @@ import android.view.animation.Interpolator; * {@link #draw(Canvas)} method.</p> */ public class EdgeEffect { + @SuppressWarnings("UnusedDeclaration") private static final String TAG = "EdgeEffect"; // Time it will take the effect to fully recede in ms @@ -57,10 +59,7 @@ public class EdgeEffect { private static final int PULL_DECAY_TIME = 1000; private static final float MAX_ALPHA = 1.f; - private static final float HELD_EDGE_ALPHA = 0.7f; private static final float HELD_EDGE_SCALE_Y = 0.5f; - private static final float HELD_GLOW_ALPHA = 0.5f; - private static final float HELD_GLOW_SCALE_Y = 0.5f; private static final float MAX_GLOW_HEIGHT = 4.f; @@ -76,7 +75,9 @@ public class EdgeEffect { private final Drawable mGlow; private int mWidth; private int mHeight; - private final int MIN_WIDTH = 300; + private int mX; + private int mY; + private static final int MIN_WIDTH = 300; private final int mMinWidth; private float mEdgeAlpha; @@ -119,6 +120,8 @@ public class EdgeEffect { private int mState = STATE_IDLE; private float mPullDistance; + + private final Rect mBounds = new Rect(); /** * Construct a new EdgeEffect with a theme appropriate for the provided context. @@ -145,6 +148,29 @@ public class EdgeEffect { } /** + * Set the position of this edge effect in pixels. This position is + * only used by {@link #getBounds()}. + * + * @param x The position of the edge effect on the X axis + * @param y The position of the edge effect on the Y axis + */ + void setPosition(int x, int y) { + mX = x; + mY = y; + } + + boolean isIdle() { + return mState == STATE_IDLE; + } + + /** + * Returns the height of the effect itself. + */ + int getHeight() { + return Math.max(mGlow.getBounds().height(), mEdge.getBounds().height()); + } + + /** * Reports if this EdgeEffect's animation is finished. If this method returns false * after a call to {@link #draw(Canvas)} the host widget should schedule another * drawing pass to continue the animation. @@ -301,7 +327,6 @@ public class EdgeEffect { update(); final int edgeHeight = mEdge.getIntrinsicHeight(); - final int edgeWidth = mEdge.getIntrinsicWidth(); final int glowHeight = mGlow.getIntrinsicHeight(); final int glowWidth = mGlow.getIntrinsicWidth(); @@ -334,9 +359,23 @@ public class EdgeEffect { } mEdge.draw(canvas); + if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) { + mState = STATE_IDLE; + } + return mState != STATE_IDLE; } + /** + * Returns the bounds of the edge effect. + */ + public Rect getBounds() { + mBounds.set(mGlow.getBounds()); + mBounds.union(mEdge.getBounds()); + mBounds.offset(mX, mY); + return mBounds; + } + private void update() { final long time = AnimationUtils.currentAnimationTimeMillis(); final float t = Math.min((time - mStartTime) / mDuration, 1.f); |