don't block attaching ReactRootView on measuring

Reviewed By: achen1

Differential Revision: D5117394

fbshipit-source-id: 00f65a59247a75d4b42240fe25935aa9bd8948b1
This commit is contained in:
Aaron Chiu 2017-05-31 02:16:43 -07:00 committed by Facebook Github Bot
parent 23a34d4c65
commit 8125ce520d
12 changed files with 31 additions and 42 deletions

View File

@ -25,7 +25,6 @@ import com.facebook.react.modules.appstate.AppStateModule;
import com.facebook.react.modules.deviceinfo.DeviceInfoModule; import com.facebook.react.modules.deviceinfo.DeviceInfoModule;
import com.facebook.react.modules.systeminfo.AndroidInfoModule; import com.facebook.react.modules.systeminfo.AndroidInfoModule;
import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.UIImplementation;
import com.facebook.react.uimanager.UIImplementationProvider; import com.facebook.react.uimanager.UIImplementationProvider;
import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManager;
@ -66,7 +65,7 @@ public class CatalystUIManagerTestCase extends ReactIntegrationTestCase {
final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
rootView.setLayoutParams( rootView.setLayoutParams(
new FrameLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels)); new FrameLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels));
uiManager.addMeasuredRootView(rootView); uiManager.addRootView(rootView);
// We add the root view by posting to the main thread so wait for that to complete so that the // We add the root view by posting to the main thread so wait for that to complete so that the
// root view tag is added to the view // root view tag is added to the view
waitForIdleSync(); waitForIdleSync();
@ -228,7 +227,7 @@ public class CatalystUIManagerTestCase extends ReactIntegrationTestCase {
public void _testCenteredText(String text) { public void _testCenteredText(String text) {
ReactRootView rootView = new ReactRootView(getContext()); ReactRootView rootView = new ReactRootView(getContext());
int rootTag = uiManager.addMeasuredRootView(rootView); int rootTag = uiManager.addRootView(rootView);
jsModule.renderCenteredTextViewTestApplication(rootTag, text); jsModule.renderCenteredTextViewTestApplication(rootTag, text);
waitForBridgeAndUIIdle(); waitForBridgeAndUIIdle();

View File

@ -27,7 +27,6 @@ import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.modules.appstate.AppStateModule; import com.facebook.react.modules.appstate.AppStateModule;
import com.facebook.react.modules.deviceinfo.DeviceInfoModule; import com.facebook.react.modules.deviceinfo.DeviceInfoModule;
import com.facebook.react.modules.systeminfo.AndroidInfoModule; import com.facebook.react.modules.systeminfo.AndroidInfoModule;
import com.facebook.react.uimanager.UIImplementation;
import com.facebook.react.uimanager.UIImplementationProvider; import com.facebook.react.uimanager.UIImplementationProvider;
import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManager;
@ -98,7 +97,7 @@ public class ProgressBarTestCase extends ReactIntegrationTestCase {
DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
mRootView.setLayoutParams( mRootView.setLayoutParams(
new FrameLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels)); new FrameLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels));
int rootTag = mUIManager.addMeasuredRootView(mRootView); int rootTag = mUIManager.addRootView(mRootView);
mInstance.getJSModule(ProgressBarTestModule.class).renderProgressBarApplication(rootTag); mInstance.getJSModule(ProgressBarTestModule.class).renderProgressBarApplication(rootTag);
waitForBridgeAndUIIdle(); waitForBridgeAndUIIdle();
} }

View File

@ -23,7 +23,6 @@ import com.facebook.react.modules.appstate.AppStateModule;
import com.facebook.react.modules.deviceinfo.DeviceInfoModule; import com.facebook.react.modules.deviceinfo.DeviceInfoModule;
import com.facebook.react.modules.systeminfo.AndroidInfoModule; import com.facebook.react.modules.systeminfo.AndroidInfoModule;
import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.UIImplementation;
import com.facebook.react.uimanager.UIImplementationProvider; import com.facebook.react.uimanager.UIImplementationProvider;
import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewManager; import com.facebook.react.uimanager.ViewManager;
@ -76,7 +75,7 @@ public class ViewRenderingTestCase extends ReactIntegrationTestCase {
.build(); .build();
mRootView = new ReactRootView(getContext()); mRootView = new ReactRootView(getContext());
mRootTag = uiManager.addMeasuredRootView(mRootView); mRootTag = uiManager.addRootView(mRootView);
} }
public void testViewRenderedWithCorrectProperties() { public void testViewRenderedWithCorrectProperties() {

View File

@ -613,7 +613,7 @@ public class ReactInstanceManager {
* be re-attached. * be re-attached.
*/ */
@ThreadConfined(UI) @ThreadConfined(UI)
public void attachMeasuredRootView(ReactRootView rootView) { public void attachRootView(ReactRootView rootView) {
UiThreadUtil.assertOnUiThread(); UiThreadUtil.assertOnUiThread();
mAttachedRootViews.add(rootView); mAttachedRootViews.add(rootView);
@ -624,7 +624,7 @@ public class ReactInstanceManager {
// If react context is being created in the background, JS application will be started // If react context is being created in the background, JS application will be started
// automatically when creation completes, as root view is part of the attached root view list. // automatically when creation completes, as root view is part of the attached root view list.
if (mCreateReactContextThread == null && mCurrentReactContext != null) { if (mCreateReactContextThread == null && mCurrentReactContext != null) {
attachMeasuredRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance()); attachRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance());
} }
} }
@ -814,7 +814,7 @@ public class ReactInstanceManager {
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START); ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START);
synchronized (mAttachedRootViews) { synchronized (mAttachedRootViews) {
for (ReactRootView rootView : mAttachedRootViews) { for (ReactRootView rootView : mAttachedRootViews) {
attachMeasuredRootViewToInstance(rootView, catalystInstance); attachRootViewToInstance(rootView, catalystInstance);
} }
} }
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END); ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END);
@ -850,16 +850,16 @@ public class ReactInstanceManager {
} }
} }
private void attachMeasuredRootViewToInstance( private void attachRootViewToInstance(
final ReactRootView rootView, final ReactRootView rootView,
CatalystInstance catalystInstance) { CatalystInstance catalystInstance) {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachMeasuredRootViewToInstance"); Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachRootViewToInstance");
if (!mSetupReactContextInBackgroundEnabled) { if (!mSetupReactContextInBackgroundEnabled) {
UiThreadUtil.assertOnUiThread(); UiThreadUtil.assertOnUiThread();
} }
UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class); UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
final int rootTag = uiManagerModule.addMeasuredRootView(rootView); final int rootTag = uiManagerModule.addRootView(rootView);
rootView.setRootViewTag(rootTag); rootView.setRootViewTag(rootTag);
rootView.runApplication(); rootView.runApplication();
Systrace.beginAsyncSection( Systrace.beginAsyncSection(

View File

@ -78,8 +78,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
private @Nullable CustomGlobalLayoutListener mCustomGlobalLayoutListener; private @Nullable CustomGlobalLayoutListener mCustomGlobalLayoutListener;
private @Nullable ReactRootViewEventListener mRootViewEventListener; private @Nullable ReactRootViewEventListener mRootViewEventListener;
private int mRootViewTag; private int mRootViewTag;
private boolean mWasMeasured = false; private boolean mIsAttachedToInstance;
private boolean mIsAttachedToInstance = false;
private final JSTouchDispatcher mJSTouchDispatcher = new JSTouchDispatcher(this); private final JSTouchDispatcher mJSTouchDispatcher = new JSTouchDispatcher(this);
public ReactRootView(Context context) { public ReactRootView(Context context) {
@ -102,7 +101,6 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec)); MeasureSpec.getSize(heightMeasureSpec));
mWasMeasured = true;
// Check if we were waiting for onMeasure to attach the root view. // Check if we were waiting for onMeasure to attach the root view.
if (mReactInstanceManager != null && !mIsAttachedToInstance) { if (mReactInstanceManager != null && !mIsAttachedToInstance) {
attachToReactInstanceManager(); attachToReactInstanceManager();
@ -222,12 +220,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
mReactInstanceManager.createReactContextInBackground(); mReactInstanceManager.createReactContextInBackground();
} }
// We need to wait for the initial onMeasure, if this view has not yet been measured, we set
// which will make this view startReactApplication itself to instance manager once onMeasure
// is called.
if (mWasMeasured) {
attachToReactInstanceManager(); attachToReactInstanceManager();
}
} finally { } finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
} }
@ -303,13 +296,12 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
} }
/** /**
* Is used by unit test to setup mWasMeasured and mIsAttachedToWindow flags, that will let this * Is used by unit test to setup mIsAttachedToWindow flags, that will let this
* view to be properly attached to catalyst instance by startReactApplication call * view to be properly attached to catalyst instance by startReactApplication call
*/ */
@VisibleForTesting @VisibleForTesting
/* package */ void simulateAttachForTesting() { /* package */ void simulateAttachForTesting() {
mIsAttachedToInstance = true; mIsAttachedToInstance = true;
mWasMeasured = true;
} }
private CustomGlobalLayoutListener getCustomGlobalLayoutListener() { private CustomGlobalLayoutListener getCustomGlobalLayoutListener() {
@ -327,7 +319,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
} }
mIsAttachedToInstance = true; mIsAttachedToInstance = true;
Assertions.assertNotNull(mReactInstanceManager).attachMeasuredRootView(this); Assertions.assertNotNull(mReactInstanceManager).attachRootView(this);
getViewTreeObserver().addOnGlobalLayoutListener(getCustomGlobalLayoutListener()); getViewTreeObserver().addOnGlobalLayoutListener(getCustomGlobalLayoutListener());
} finally { } finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
@ -362,6 +354,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
private int mDeviceRotation = 0; private int mDeviceRotation = 0;
/* package */ CustomGlobalLayoutListener() { /* package */ CustomGlobalLayoutListener() {
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(getContext().getApplicationContext());
mVisibleViewArea = new Rect(); mVisibleViewArea = new Rect();
mMinKeyboardHeightDetected = (int) PixelUtil.toPixelFromDIP(60); mMinKeyboardHeightDetected = (int) PixelUtil.toPixelFromDIP(60);
} }

View File

@ -487,7 +487,7 @@ public class NativeViewHierarchyManager {
} }
/** /**
* See {@link UIManagerModule#addMeasuredRootView}. * See {@link UIManagerModule#addRootView}.
*/ */
public synchronized void addRootView( public synchronized void addRootView(
int tag, int tag,
@ -504,7 +504,7 @@ public class NativeViewHierarchyManager {
throw new IllegalViewOperationException( throw new IllegalViewOperationException(
"Trying to add a root view with an explicit id already set. React Native uses " + "Trying to add a root view with an explicit id already set. React Native uses " +
"the id field to track react tags and will overwrite this field. If that is fine, " + "the id field to track react tags and will overwrite this field. If that is fine, " +
"explicitly overwrite the id field to View.NO_ID before calling addMeasuredRootView."); "explicitly overwrite the id field to View.NO_ID before calling addRootView.");
} }
mTagsToViews.put(tag, view); mTagsToViews.put(tag, view);

View File

@ -52,5 +52,4 @@ public class SizeMonitoringFrameLayout extends FrameLayout {
mOnSizeChangedListener.onSizeChanged(w, h, oldw, oldh); mOnSizeChangedListener.onSizeChanged(w, h, oldw, oldh);
} }
} }
} }

View File

@ -14,7 +14,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import com.facebook.common.logging.FLog; import com.facebook.common.logging.FLog;
import com.facebook.yoga.YogaDirection;
import com.facebook.infer.annotation.Assertions; import com.facebook.infer.annotation.Assertions;
import com.facebook.react.animation.Animation; import com.facebook.react.animation.Animation;
import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Arguments;
@ -30,6 +29,7 @@ import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugL
import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.systrace.Systrace; import com.facebook.systrace.Systrace;
import com.facebook.systrace.SystraceMessage; import com.facebook.systrace.SystraceMessage;
import com.facebook.yoga.YogaDirection;
/** /**
* An class that is used to receive React commands from JS and translate them into a * An class that is used to receive React commands from JS and translate them into a

View File

@ -181,13 +181,13 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
* Note that this must be called after getWidth()/getHeight() actually return something. See * Note that this must be called after getWidth()/getHeight() actually return something. See
* CatalystApplicationFragment as an example. * CatalystApplicationFragment as an example.
* *
* TODO(6242243): Make addMeasuredRootView thread safe * TODO(6242243): Make addRootView thread safe
* NB: this method is horribly not-thread-safe. * NB: this method is horribly not-thread-safe.
*/ */
public int addMeasuredRootView(final SizeMonitoringFrameLayout rootView) { public int addRootView(final SizeMonitoringFrameLayout rootView) {
Systrace.beginSection( Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"UIManagerModule.addMeasuredRootView"); "UIManagerModule.addRootView");
final int tag = mNextRootViewTag; final int tag = mNextRootViewTag;
mNextRootViewTag += ROOT_VIEW_TAG_INCREMENT; mNextRootViewTag += ROOT_VIEW_TAG_INCREMENT;

View File

@ -151,7 +151,7 @@ public class UIManagerModuleTest {
ReactRootView rootView = ReactRootView rootView =
new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
int rootTag = uiManager.addMeasuredRootView(rootView); int rootTag = uiManager.addRootView(rootView);
int viewTag = rootTag + 1; int viewTag = rootTag + 1;
int subViewTag = viewTag + 1; int subViewTag = viewTag + 1;
@ -609,7 +609,7 @@ public class UIManagerModuleTest {
UIManagerModule uiManager = getUIManagerModule(); UIManagerModule uiManager = getUIManagerModule();
ReactRootView rootView = ReactRootView rootView =
new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
int rootTag = uiManager.addMeasuredRootView(rootView); int rootTag = uiManager.addRootView(rootView);
final int containerTag = rootTag + 1; final int containerTag = rootTag + 1;
final int containerSiblingTag = containerTag + 1; final int containerSiblingTag = containerTag + 1;
@ -662,7 +662,7 @@ public class UIManagerModuleTest {
private ViewGroup createSimpleTextHierarchy(UIManagerModule uiManager, String text) { private ViewGroup createSimpleTextHierarchy(UIManagerModule uiManager, String text) {
ReactRootView rootView = ReactRootView rootView =
new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
int rootTag = uiManager.addMeasuredRootView(rootView); int rootTag = uiManager.addRootView(rootView);
int textTag = rootTag + 1; int textTag = rootTag + 1;
int rawTextTag = textTag + 1; int rawTextTag = textTag + 1;
@ -701,7 +701,7 @@ public class UIManagerModuleTest {
private TestMoveDeleteHierarchy createMoveDeleteHierarchy(UIManagerModule uiManager) { private TestMoveDeleteHierarchy createMoveDeleteHierarchy(UIManagerModule uiManager) {
ReactRootView rootView = new ReactRootView(mReactContext); ReactRootView rootView = new ReactRootView(mReactContext);
int rootTag = uiManager.addMeasuredRootView(rootView); int rootTag = uiManager.addRootView(rootView);
TestMoveDeleteHierarchy hierarchy = new TestMoveDeleteHierarchy(rootView, rootTag); TestMoveDeleteHierarchy hierarchy = new TestMoveDeleteHierarchy(rootView, rootTag);

View File

@ -379,7 +379,7 @@ public class ReactTextTest {
JavaOnlyMap textProps, JavaOnlyMap textProps,
JavaOnlyMap rawTextProps) { JavaOnlyMap rawTextProps) {
ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application); ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application);
int rootTag = uiManager.addMeasuredRootView(rootView); int rootTag = uiManager.addRootView(rootView);
int textTag = rootTag + 1; int textTag = rootTag + 1;
int rawTextTag = textTag + 1; int rawTextTag = textTag + 1;

View File

@ -91,7 +91,7 @@ public class TextInputTest {
ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application); ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application);
rootView.setLayoutParams(new ReactRootView.LayoutParams(100, 100)); rootView.setLayoutParams(new ReactRootView.LayoutParams(100, 100));
int rootTag = uiManager.addMeasuredRootView(rootView); int rootTag = uiManager.addRootView(rootView);
int textInputTag = rootTag + 1; int textInputTag = rootTag + 1;
final String hintStr = "placeholder text"; final String hintStr = "placeholder text";
@ -125,7 +125,7 @@ public class TextInputTest {
ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application); ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application);
rootView.setLayoutParams(new ReactRootView.LayoutParams(100, 100)); rootView.setLayoutParams(new ReactRootView.LayoutParams(100, 100));
int rootTag = uiManager.addMeasuredRootView(rootView); int rootTag = uiManager.addRootView(rootView);
int textInputTag = rootTag + 1; int textInputTag = rootTag + 1;
final String hintStr = "placeholder text"; final String hintStr = "placeholder text";