From c54775791353e37aa621cf5dd6cf7d82c2762799 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Wed, 7 Oct 2020 23:10:48 -0700 Subject: [PATCH] Perf improvement: don't call uiManager.updateRootLayoutSpecs on every ReactRootView.onLayout Summary: In D23640968 (https://github.com/facebook/react-native/commit/78b42d7fb7180102c1e8ec917dcccd2d9d4076db) I introduced a mechanism to update offsetX/offsetY whenever onMeasure/onLayout were called, to ensure that `measureInWindow` had the correct metrics and would work properly. However, now `uiManager.updateRootLayoutSpecs` gets spammed and is called too often. For example, whenever a TextInput is focused/blurred, `uiManager.updateRootLayoutSpecs` may be called 5+ times even though the measure specs/offsets may only change once. Thus, we just compare with previous values before calling into the UIManager. This should give us a very small perf improvement. Changelog: [Internal] Reviewed By: shergin Differential Revision: D24176867 fbshipit-source-id: f0dcc816e651a843607e9e5d40d8f3489894d4ba --- .../com/facebook/react/ReactRootView.java | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index c21bffc720a..30b322a68a3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -95,6 +95,8 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot { private int mHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); private int mLastWidth = 0; private int mLastHeight = 0; + private int mLastOffsetX = Integer.MIN_VALUE; + private int mLastOffsetY = Integer.MIN_VALUE; private @UIManagerType int mUIManagerType = DEFAULT; public ReactRootView(Context context) { @@ -162,7 +164,7 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot { if (mReactInstanceManager != null && !mIsAttachedToInstance) { attachToReactInstanceManager(); } else if (measureSpecsUpdated || mLastWidth != width || mLastHeight != height) { - updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec); + updateRootLayoutSpecs(true, mWidthMeasureSpec, mHeightMeasureSpec); } mLastWidth = width; mLastHeight = height; @@ -296,7 +298,7 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot { // In Fabric, update LayoutSpecs just so we update the offsetX and offsetY. if (mWasMeasured && getUIManagerType() == FABRIC) { - updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec); + updateRootLayoutSpecs(false, mWidthMeasureSpec, mHeightMeasureSpec); } } @@ -423,7 +425,17 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot { return new Point(locationInWindow[0], locationInWindow[1]); } - private void updateRootLayoutSpecs(final int widthMeasureSpec, final int heightMeasureSpec) { + /** + * Call whenever measure specs change, or if you want to force an update of offsetX/offsetY. If + * measureSpecsChanged is false and the offsetX/offsetY don't change, updateRootLayoutSpecs will + * not be called on the UIManager as a perf optimization. + * + * @param measureSpecsChanged + * @param widthMeasureSpec + * @param heightMeasureSpec + */ + private void updateRootLayoutSpecs( + boolean measureSpecsChanged, final int widthMeasureSpec, final int heightMeasureSpec) { if (mReactInstanceManager == null) { FLog.w(TAG, "Unable to update root layout specs for uninitialized ReactInstanceManager"); return; @@ -445,8 +457,12 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot { offsetY = viewportOffset.y; } - uiManager.updateRootLayoutSpecs( - getRootViewTag(), widthMeasureSpec, heightMeasureSpec, offsetX, offsetY); + if (measureSpecsChanged || offsetX != mLastOffsetX || offsetY != mLastOffsetY) { + uiManager.updateRootLayoutSpecs( + getRootViewTag(), widthMeasureSpec, heightMeasureSpec, offsetX, offsetY); + } + mLastOffsetX = offsetX; + mLastOffsetY = offsetY; } } } @@ -558,7 +574,7 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot { String jsAppModuleName = getJSModuleName(); if (mWasMeasured) { - updateRootLayoutSpecs(mWidthMeasureSpec, mHeightMeasureSpec); + updateRootLayoutSpecs(true, mWidthMeasureSpec, mHeightMeasureSpec); } WritableNativeMap appParams = new WritableNativeMap();