From 9cefbda11ee5308145d58b0b99ced0f66a0b1cf9 Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Tue, 14 Oct 2014 19:15:18 -0700 Subject: [PATCH] View measurement optimization If a view hasn't explicitly requested layout and it's asked to measure with MeasureSpec.EXACTLY in both dimensions and sizes that match its current measured size, the measure operation is a no-op. This helps out a number of ViewGroups that perform initial speculative measurements with AT_MOST or UNSPECIFIED followed by looping over child views and measuring EXACTLY to lock in the final measurement with perhaps some extra leftover space distributed. In practice this happens a fair bit, especially for views high up in the view hierarchy. This optimization allows ViewGroup measurement code to be a little cleaner in not having to keep track of this on its own. Change-Id: I88ff46a7d37aeda7a4cd16204b68cab0d051b341 --- core/java/android/view/View.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 8db5dd1a6a419..8e58cd656f0cf 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -17418,17 +17418,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback, long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); - if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT || - widthMeasureSpec != mOldWidthMeasureSpec || - heightMeasureSpec != mOldHeightMeasureSpec) { + final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; + final boolean isExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY && + MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; + final boolean matchingSize = isExactly && + getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) && + getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); + if (forceLayout || !matchingSize && + (widthMeasureSpec != mOldWidthMeasureSpec || + heightMeasureSpec != mOldHeightMeasureSpec)) { // first clears the measured dimension flag mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; resolveRtlPropertiesIfNeeded(); - int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 : - mMeasureCache.indexOfKey(key); + int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); if (cacheIndex < 0 || sIgnoreMeasureCache) { // measure ourselves, this should set the measured dimension flag back onMeasure(widthMeasureSpec, heightMeasureSpec);