From 7ae2fee6e1988ec12a8146a09a0053aff86a4ee2 Mon Sep 17 00:00:00 2001 From: MOVZX Date: Fri, 2 Jan 2026 23:08:41 +0700 Subject: [PATCH] AbsListView: Improve scrolling cache Scrolling cache helps make short scrolls/flings smooth but will cause stutter when long flings are made. This patch disables scrolling cache when long flings are made. This patch also fixes a related bug where scrolling cache will not be enabled properly when transitioning from flinging to scrolling. Patch Set 2: Calculate threshold based on maximum velocity (Sang Tae Park) Change-Id: Iad52a35120212c871ffd35df6184aeb678ee44aa Signed-off-by: Alex Naidis Signed-off-by: MOVZX --- core/java/android/widget/AbsListView.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index db1c28bb3fbb6..5636be22a28b0 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -697,6 +697,7 @@ public abstract class AbsListView extends AdapterView implements Te private int mMinimumVelocity; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051740) private int mMaximumVelocity; + private int mDecacheThreshold; private float mVelocityScale = 1.0f; final boolean[] mIsScrap = new boolean[1]; @@ -1011,6 +1012,7 @@ public abstract class AbsListView extends AdapterView implements Te mVerticalScrollFactor = configuration.getScaledVerticalScrollFactor(); mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); + mDecacheThreshold = mMaximumVelocity / 2; mOverscrollDistance = configuration.getScaledOverscrollDistance(); mOverflingDistance = configuration.getScaledOverflingDistance(); @@ -4965,7 +4967,7 @@ public abstract class AbsListView extends AdapterView implements Te // Keep the fling alive a little longer postDelayed(this, FLYWHEEL_TIMEOUT); } else { - endFling(); + endFling(false); // Don't disable the scrolling cache right after it was enabled mTouchMode = TOUCH_MODE_SCROLL; reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); } @@ -4985,6 +4987,10 @@ public abstract class AbsListView extends AdapterView implements Te // Use AbsListView#fling(int) instead @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void start(int initialVelocity) { + if (Math.abs(initialVelocity) > mDecacheThreshold) { + // For long flings, scrolling cache causes stutter, so don't use it + clearScrollingCache(); + } int initialY = initialVelocity < 0 ? Integer.MAX_VALUE : 0; mLastFlingY = initialY; mScroller.setInterpolator(null); @@ -5065,6 +5071,10 @@ public abstract class AbsListView extends AdapterView implements Te // To interrupt a fling early you should use smoothScrollBy(0,0) instead @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void endFling() { + endFling(true); + } + + void endFling(boolean clearCache) { mTouchMode = TOUCH_MODE_REST; removeCallbacks(this); @@ -5073,7 +5083,8 @@ public abstract class AbsListView extends AdapterView implements Te if (!mSuppressIdleStateChangeCall) { reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); } - clearScrollingCache(); + if (clearCache) + clearScrollingCache(); mScroller.abortAnimation(); if (mFlingStrictSpan != null) {