Skip to content

Commit cc3e27d

Browse files
Emily Janzerfacebook-github-bot
Emily Janzer
authored andcommitted
Don't update dimensions for a new ReactRootView if they haven't changed
Summary: ReactRootView currently caches the last seen DisplayMetrics so we can compare them against the current values in DisplayMetricsHolder to determine if the screen dimensions have changed. (If they have changed, we emit an event to notify JS of the new dimensions). However, ReactRootView initializes these member variables with empty DisplayMetrics, which means that the first time we check against them in onGlobalLayout, we will *always* emit an event to JS. This seems reasonable if you only have one ReactRootView, but if you create a new RRV for each RN screen in your app, then you're going to get updated dimensions on each navigation event, even though the screen dimensions have probably not changed. In this diff, I'm no longer storing the DisplayMetrics in ReactRootView at all, but instead am using temporary variables to check the new DisplayMetrics values against the old. Changelog: [Android][Fixed] Only update dimensions in ReactRootView if they've changed Reviewed By: JoshuaGross, mdvacca Differential Revision: D19395326 fbshipit-source-id: c01aee73064764503c9b49208032c790b83a1d29
1 parent a89a553 commit cc3e27d

File tree

2 files changed

+14
-33
lines changed

2 files changed

+14
-33
lines changed

ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java

+2-30
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@
1515
import android.content.Context;
1616
import android.graphics.Canvas;
1717
import android.graphics.Rect;
18-
import android.os.Build;
1918
import android.os.Bundle;
2019
import android.util.AttributeSet;
21-
import android.util.DisplayMetrics;
2220
import android.view.KeyEvent;
2321
import android.view.MotionEvent;
2422
import android.view.Surface;
@@ -683,8 +681,6 @@ private class CustomGlobalLayoutListener implements ViewTreeObserver.OnGlobalLay
683681

684682
private int mKeyboardHeight = 0;
685683
private int mDeviceRotation = 0;
686-
private DisplayMetrics mWindowMetrics = new DisplayMetrics();
687-
private DisplayMetrics mScreenMetrics = new DisplayMetrics();
688684

689685
/* package */ CustomGlobalLayoutListener() {
690686
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(getContext().getApplicationContext());
@@ -749,32 +745,8 @@ private void checkForDeviceOrientationChanges() {
749745
}
750746

751747
private void checkForDeviceDimensionsChanges() {
752-
// Get current display metrics.
753-
DisplayMetricsHolder.initDisplayMetrics(getContext());
754-
// Check changes to both window and screen display metrics since they may not update at the
755-
// same time.
756-
if (!areMetricsEqual(mWindowMetrics, DisplayMetricsHolder.getWindowDisplayMetrics())
757-
|| !areMetricsEqual(mScreenMetrics, DisplayMetricsHolder.getScreenDisplayMetrics())) {
758-
mWindowMetrics.setTo(DisplayMetricsHolder.getWindowDisplayMetrics());
759-
mScreenMetrics.setTo(DisplayMetricsHolder.getScreenDisplayMetrics());
760-
emitUpdateDimensionsEvent();
761-
}
762-
}
763-
764-
private boolean areMetricsEqual(DisplayMetrics displayMetrics, DisplayMetrics otherMetrics) {
765-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
766-
return displayMetrics.equals(otherMetrics);
767-
} else {
768-
// DisplayMetrics didn't have an equals method before API 17.
769-
// Check all public fields manually.
770-
return displayMetrics.widthPixels == otherMetrics.widthPixels
771-
&& displayMetrics.heightPixels == otherMetrics.heightPixels
772-
&& displayMetrics.density == otherMetrics.density
773-
&& displayMetrics.densityDpi == otherMetrics.densityDpi
774-
&& displayMetrics.scaledDensity == otherMetrics.scaledDensity
775-
&& displayMetrics.xdpi == otherMetrics.xdpi
776-
&& displayMetrics.ydpi == otherMetrics.ydpi;
777-
}
748+
// DeviceInfoModule caches the last dimensions emitted to JS, so we don't need to check here.
749+
emitUpdateDimensionsEvent();
778750
}
779751

780752
private void emitOrientationChanged(final int newRotation) {

ReactAndroid/src/main/java/com/facebook/react/modules/deviceinfo/DeviceInfoModule.java

+12-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import com.facebook.react.bridge.ReactContextBaseJavaModule;
1515
import com.facebook.react.bridge.ReactNoCrashSoftException;
1616
import com.facebook.react.bridge.ReactSoftException;
17+
import com.facebook.react.bridge.ReadableMap;
18+
import com.facebook.react.bridge.WritableNativeMap;
1719
import com.facebook.react.module.annotations.ReactModule;
1820
import com.facebook.react.modules.core.DeviceEventManagerModule;
1921
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
@@ -30,6 +32,7 @@ public class DeviceInfoModule extends ReactContextBaseJavaModule
3032

3133
private @Nullable ReactApplicationContext mReactApplicationContext;
3234
private float mFontScale;
35+
private @Nullable ReadableMap mPreviousDisplayMetrics;
3336

3437
public DeviceInfoModule(ReactApplicationContext reactContext) {
3538
super(reactContext);
@@ -83,9 +86,15 @@ public void emitUpdateDimensionsEvent() {
8386
}
8487

8588
if (mReactApplicationContext.hasActiveCatalystInstance()) {
86-
mReactApplicationContext
87-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
88-
.emit("didUpdateDimensions", DisplayMetricsHolder.getDisplayMetricsNativeMap(mFontScale));
89+
// Don't emit an event to JS if the dimensions haven't changed
90+
WritableNativeMap displayMetrics =
91+
DisplayMetricsHolder.getDisplayMetricsNativeMap(mFontScale);
92+
if (!displayMetrics.equals(mPreviousDisplayMetrics)) {
93+
mReactApplicationContext
94+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
95+
.emit("didUpdateDimensions", displayMetrics);
96+
mPreviousDisplayMetrics = displayMetrics;
97+
}
8998
} else {
9099
ReactSoftException.logSoftException(
91100
NAME,

0 commit comments

Comments
 (0)