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
This commit is contained in:
Joshua Gross
2020-10-07 23:12:55 -07:00
committed by Facebook GitHub Bot
parent 7c2f46ce3f
commit c547757913
@@ -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();