mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-03-04 22:36:16 +08:00
Detach dependency on RRV for Instance Manager
Summary: Remove dependency on ReactRootView in ReactInstanceManager by creating a rough interface (ReactRoot) so that either a Surface or ReactRootView can be attached to ReactInstanceManager. Reviewed By: ejanzer, mdvacca Differential Revision: D14158890 fbshipit-source-id: b7ab4654b1e0ef8343230a3c15023653a7f23a4b
This commit is contained in:
committed by
Facebook Github Bot
parent
417adf526f
commit
135ba492fb
@@ -35,6 +35,7 @@ rn_android_library(
|
||||
react_native_target("java/com/facebook/react/modules/deviceinfo:deviceinfo"),
|
||||
react_native_target("java/com/facebook/react/modules/systeminfo:systeminfo"),
|
||||
react_native_target("java/com/facebook/react/modules/toast:toast"),
|
||||
react_native_target("java/com/facebook/react/surface:surface"),
|
||||
react_native_target("java/com/facebook/react/uimanager:uimanager"),
|
||||
react_native_target("java/com/facebook/react/module/annotations:annotations"),
|
||||
react_native_target("java/com/facebook/react/views/imagehelper:imagehelper"),
|
||||
|
||||
@@ -84,7 +84,9 @@ import com.facebook.react.modules.core.ReactChoreographer;
|
||||
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
|
||||
import com.facebook.react.modules.fabric.ReactFabric;
|
||||
import com.facebook.react.packagerconnection.RequestHandler;
|
||||
import com.facebook.react.surface.ReactStage;
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder;
|
||||
import com.facebook.react.uimanager.ReactRoot;
|
||||
import com.facebook.react.uimanager.UIImplementationProvider;
|
||||
import com.facebook.react.uimanager.UIManagerHelper;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
@@ -99,7 +101,6 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
@@ -135,8 +136,8 @@ public class ReactInstanceManager {
|
||||
void onReactContextInitialized(ReactContext context);
|
||||
}
|
||||
|
||||
private final Set<ReactRootView> mAttachedRootViews = Collections.synchronizedSet(
|
||||
new HashSet<ReactRootView>());
|
||||
private final Set<ReactRoot> mAttachedReactRoots = Collections.synchronizedSet(
|
||||
new HashSet<ReactRoot>());
|
||||
|
||||
private volatile LifecycleState mLifecycleState;
|
||||
|
||||
@@ -710,45 +711,49 @@ public class ReactInstanceManager {
|
||||
mDevSupportManager.showDevOptionsDialog();
|
||||
}
|
||||
|
||||
private void clearReactRoot(ReactRoot reactRoot) {
|
||||
reactRoot.getRootViewGroup().removeAllViews();
|
||||
reactRoot.getRootViewGroup().setId(View.NO_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach given {@param rootView} to a catalyst instance manager and start JS application using
|
||||
* Attach given {@param reactRoot} to a catalyst instance manager and start JS application using
|
||||
* JS module provided by {@link ReactRootView#getJSModuleName}. If the react context is currently
|
||||
* being (re)-created, or if react context has not been created yet, the JS application associated
|
||||
* with the provided root view will be started asynchronously, i.e this method won't block.
|
||||
* This view will then be tracked by this manager and in case of catalyst instance restart it will
|
||||
* with the provided reactRoot reactRoot will be started asynchronously, i.e this method won't block.
|
||||
* This reactRoot will then be tracked by this manager and in case of catalyst instance restart it will
|
||||
* be re-attached.
|
||||
*/
|
||||
@ThreadConfined(UI)
|
||||
public void attachRootView(ReactRootView rootView) {
|
||||
public void attachRootView(ReactRoot reactRoot) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
mAttachedRootViews.add(rootView);
|
||||
mAttachedReactRoots.add(reactRoot);
|
||||
|
||||
// Reset view content as it's going to be populated by the application content from JS.
|
||||
rootView.removeAllViews();
|
||||
rootView.setId(View.NO_ID);
|
||||
// Reset reactRoot content as it's going to be populated by the application content from JS.
|
||||
clearReactRoot(reactRoot);
|
||||
|
||||
// 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 reactRoot reactRoot is part of the attached reactRoot reactRoot list.
|
||||
ReactContext currentContext = getCurrentReactContext();
|
||||
if (mCreateReactContextThread == null && currentContext != null) {
|
||||
attachRootViewToInstance(rootView);
|
||||
attachRootViewToInstance(reactRoot);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach given {@param rootView} from current catalyst instance. It's safe to call this method
|
||||
* multiple times on the same {@param rootView} - in that case view will be detached with the
|
||||
* Detach given {@param reactRoot} from current catalyst instance. It's safe to call this method
|
||||
* multiple times on the same {@param reactRoot} - in that case view will be detached with the
|
||||
* first call.
|
||||
*/
|
||||
@ThreadConfined(UI)
|
||||
public void detachRootView(ReactRootView rootView) {
|
||||
public void detachRootView(ReactRoot reactRoot) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
synchronized (mAttachedRootViews) {
|
||||
if (mAttachedRootViews.contains(rootView)) {
|
||||
synchronized (mAttachedReactRoots) {
|
||||
if (mAttachedReactRoots.contains(reactRoot)) {
|
||||
ReactContext currentContext = getCurrentReactContext();
|
||||
mAttachedRootViews.remove(rootView);
|
||||
mAttachedReactRoots.remove(reactRoot);
|
||||
if (currentContext != null && currentContext.hasActiveCatalystInstance()) {
|
||||
detachViewFromInstance(rootView, currentContext.getCatalystInstance());
|
||||
detachViewFromInstance(reactRoot, currentContext.getCatalystInstance());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -908,7 +913,7 @@ public class ReactInstanceManager {
|
||||
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
|
||||
Log.d(ReactConstants.TAG, "ReactInstanceManager.runCreateReactContextOnNewThread()");
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
synchronized (mAttachedRootViews) {
|
||||
synchronized (mAttachedReactRoots) {
|
||||
synchronized (mReactContextLock) {
|
||||
if (mCurrentReactContext != null) {
|
||||
tearDownReactContext(mCurrentReactContext);
|
||||
@@ -985,7 +990,7 @@ public class ReactInstanceManager {
|
||||
ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_END);
|
||||
ReactMarker.logMarker(SETUP_REACT_CONTEXT_START);
|
||||
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "setupReactContext");
|
||||
synchronized (mAttachedRootViews) {
|
||||
synchronized (mAttachedReactRoots) {
|
||||
synchronized (mReactContextLock) {
|
||||
mCurrentReactContext = Assertions.assertNotNull(reactContext);
|
||||
}
|
||||
@@ -999,8 +1004,8 @@ public class ReactInstanceManager {
|
||||
moveReactContextToCurrentLifecycleState();
|
||||
|
||||
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START);
|
||||
for (ReactRootView rootView : mAttachedRootViews) {
|
||||
attachRootViewToInstance(rootView);
|
||||
for (ReactRoot reactRoot : mAttachedReactRoots) {
|
||||
attachRootViewToInstance(reactRoot);
|
||||
}
|
||||
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END);
|
||||
}
|
||||
@@ -1038,47 +1043,46 @@ public class ReactInstanceManager {
|
||||
});
|
||||
}
|
||||
|
||||
private void attachRootViewToInstance(final ReactRootView rootView) {
|
||||
private void attachRootViewToInstance(final ReactRoot reactRoot) {
|
||||
Log.d(ReactConstants.TAG, "ReactInstanceManager.attachRootViewToInstance()");
|
||||
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachRootViewToInstance");
|
||||
UIManager uiManagerModule = UIManagerHelper.getUIManager(mCurrentReactContext, rootView.getUIManagerType());
|
||||
UIManager uiManagerModule = UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType());
|
||||
|
||||
@Nullable Bundle initialProperties = rootView.getAppProperties();
|
||||
@Nullable Bundle initialProperties = reactRoot.getAppProperties();
|
||||
final int rootTag = uiManagerModule.addRootView(
|
||||
rootView.getView(),
|
||||
reactRoot.getRootViewGroup(),
|
||||
initialProperties == null ?
|
||||
new WritableNativeMap() : Arguments.fromBundle(initialProperties),
|
||||
rootView.getInitialUITemplate());
|
||||
rootView.setRootViewTag(rootTag);
|
||||
rootView.runApplication();
|
||||
reactRoot.getInitialUITemplate());
|
||||
reactRoot.setRootViewTag(rootTag);
|
||||
reactRoot.runApplication();
|
||||
Systrace.beginAsyncSection(
|
||||
TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||
"pre_rootView.onAttachedToReactInstance",
|
||||
rootTag);
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Systrace.endAsyncSection(
|
||||
TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||
"pre_rootView.onAttachedToReactInstance",
|
||||
rootTag);
|
||||
rootView.onAttachedToReactInstance();
|
||||
}
|
||||
});
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Systrace.endAsyncSection(
|
||||
TRACE_TAG_REACT_JAVA_BRIDGE, "pre_rootView.onAttachedToReactInstance", rootTag);
|
||||
reactRoot.onStage(ReactStage.ON_ATTACH_TO_INSTANCE);
|
||||
}
|
||||
});
|
||||
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
|
||||
private void detachViewFromInstance(
|
||||
ReactRootView rootView,
|
||||
ReactRoot reactRoot,
|
||||
CatalystInstance catalystInstance) {
|
||||
Log.d(ReactConstants.TAG, "ReactInstanceManager.detachViewFromInstance()");
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
if (rootView.getUIManagerType() == FABRIC) {
|
||||
if (reactRoot.getUIManagerType() == FABRIC) {
|
||||
catalystInstance.getJSModule(ReactFabric.class)
|
||||
.unmountComponentAtNode(rootView.getRootViewTag());
|
||||
.unmountComponentAtNode(reactRoot.getRootViewTag());
|
||||
} else {
|
||||
catalystInstance.getJSModule(AppRegistry.class)
|
||||
.unmountApplicationComponentAtRootTag(rootView.getRootViewTag());
|
||||
.unmountApplicationComponentAtRootTag(reactRoot.getRootViewTag());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1090,10 +1094,9 @@ public class ReactInstanceManager {
|
||||
reactContext.onHostPause();
|
||||
}
|
||||
|
||||
synchronized (mAttachedRootViews) {
|
||||
for (ReactRootView rootView : mAttachedRootViews) {
|
||||
rootView.removeAllViews();
|
||||
rootView.setId(View.NO_ID);
|
||||
synchronized (mAttachedReactRoots) {
|
||||
for (ReactRoot reactRoot : mAttachedReactRoots) {
|
||||
clearReactRoot(reactRoot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,11 +41,13 @@ import com.facebook.react.common.annotations.VisibleForTesting;
|
||||
import com.facebook.react.modules.appregistry.AppRegistry;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.modules.deviceinfo.DeviceInfoModule;
|
||||
import com.facebook.react.surface.ReactStage;
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder;
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException;
|
||||
import com.facebook.react.uimanager.JSTouchDispatcher;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.RootView;
|
||||
import com.facebook.react.uimanager.ReactRoot;
|
||||
import com.facebook.react.uimanager.UIManagerHelper;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.common.UIManagerType;
|
||||
@@ -65,7 +67,7 @@ import javax.annotation.Nullable;
|
||||
* subsequent touch events related to that gesture (in case when JS code wants to handle that
|
||||
* gesture).
|
||||
*/
|
||||
public class ReactRootView extends FrameLayout implements RootView {
|
||||
public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
|
||||
|
||||
/**
|
||||
* Listener interface for react root view events
|
||||
@@ -124,11 +126,6 @@ public class ReactRootView extends FrameLayout implements RootView {
|
||||
setClipChildren(false);
|
||||
}
|
||||
|
||||
public View getView() {
|
||||
// TODO add mUseSurface to return surface here
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (mUseSurface) {
|
||||
@@ -347,6 +344,11 @@ public class ReactRootView extends FrameLayout implements RootView {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewGroup getRootViewGroup() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@see #startReactApplication(ReactInstanceManager, String, android.os.Bundle)}
|
||||
*/
|
||||
@@ -433,6 +435,17 @@ public class ReactRootView extends FrameLayout implements RootView {
|
||||
mShouldLogContentAppeared = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStage(int stage) {
|
||||
switch(stage) {
|
||||
case ReactStage.ON_ATTACH_TO_INSTANCE:
|
||||
onAttachedToReactInstance();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void onAttachedToReactInstance() {
|
||||
// Create the touch dispatcher here instead of having it always available, to make sure
|
||||
// that all touch events are only passed to JS after React/JS side is ready to consume
|
||||
@@ -452,10 +465,12 @@ public class ReactRootView extends FrameLayout implements RootView {
|
||||
return Assertions.assertNotNull(mJSModuleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Bundle getAppProperties() {
|
||||
return mAppProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getInitialUITemplate() {
|
||||
return mInitialUITemplate;
|
||||
}
|
||||
@@ -472,7 +487,8 @@ public class ReactRootView extends FrameLayout implements RootView {
|
||||
* Calls into JS to start the React application. Can be called multiple times with the
|
||||
* same rootTag, which will re-render the application from the root.
|
||||
*/
|
||||
/* package */ void runApplication() {
|
||||
@Override
|
||||
public void runApplication() {
|
||||
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactRootView.runApplication");
|
||||
try {
|
||||
if (mReactInstanceManager == null || !mIsAttachedToInstance) {
|
||||
@@ -581,6 +597,7 @@ public class ReactRootView extends FrameLayout implements RootView {
|
||||
mUIManagerType = isFabric ? FABRIC : DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @UIManagerType int getUIManagerType() {
|
||||
return mUIManagerType;
|
||||
}
|
||||
|
||||
20
ReactAndroid/src/main/java/com/facebook/react/surface/BUCK
Normal file
20
ReactAndroid/src/main/java/com/facebook/react/surface/BUCK
Normal file
@@ -0,0 +1,20 @@
|
||||
load("@fbsource//tools/build_defs/oss:rn_defs.bzl", "YOGA_TARGET", "react_native_dep", "react_native_target", "rn_android_library")
|
||||
|
||||
rn_android_library(
|
||||
name = "surface",
|
||||
srcs = glob(["*.java"]),
|
||||
is_androidx = True,
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
deps = [
|
||||
YOGA_TARGET,
|
||||
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
|
||||
react_native_dep("third-party/android/support-annotations:android-support-annotations"),
|
||||
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
|
||||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||
react_native_target("java/com/facebook/react/bridge:bridge"),
|
||||
react_native_target("java/com/facebook/react/common:common"),
|
||||
react_native_target("java/com/facebook/react/module/annotations:annotations"),
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.facebook.react.surface;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
/**
|
||||
* The stage of the Surface
|
||||
*/
|
||||
@Retention(SOURCE)
|
||||
@IntDef({
|
||||
ReactStage.SURFACE_DID_INITIALIZE,
|
||||
ReactStage.BRIDGE_DID_LOAD,
|
||||
ReactStage.MODULE_DID_LOAD,
|
||||
ReactStage.SURFACE_DID_RUN,
|
||||
ReactStage.SURFACE_DID_INITIAL_RENDERING,
|
||||
ReactStage.SURFACE_DID_INITIAL_LAYOUT,
|
||||
ReactStage.SURFACE_DID_INITIAL_MOUNTING,
|
||||
ReactStage.SURFACE_DID_STOP
|
||||
})
|
||||
public @interface ReactStage {
|
||||
int SURFACE_DID_INITIALIZE = 0;
|
||||
int BRIDGE_DID_LOAD = 1;
|
||||
int MODULE_DID_LOAD = 2;
|
||||
int SURFACE_DID_RUN = 3;
|
||||
int SURFACE_DID_INITIAL_RENDERING = 4;
|
||||
int SURFACE_DID_INITIAL_LAYOUT = 5;
|
||||
int SURFACE_DID_INITIAL_MOUNTING = 6;
|
||||
int SURFACE_DID_STOP = 7;
|
||||
|
||||
int ON_ATTACH_TO_INSTANCE = 101;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.ViewGroup;
|
||||
import com.facebook.react.uimanager.common.UIManagerType;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for the root native view of a React native application
|
||||
*/
|
||||
public interface ReactRoot {
|
||||
|
||||
/**
|
||||
* Return cached launch properties for app
|
||||
*/
|
||||
@Nullable Bundle getAppProperties();
|
||||
@Nullable String getInitialUITemplate();
|
||||
|
||||
/**
|
||||
* Fabric or Default UI Manager, see {@link UIManagerType}
|
||||
*/
|
||||
@UIManagerType int getUIManagerType();
|
||||
|
||||
int getRootViewTag();
|
||||
|
||||
void setRootViewTag(int rootViewTag);
|
||||
|
||||
/**
|
||||
* Calls into JS to start the React application.
|
||||
*/
|
||||
void runApplication();
|
||||
|
||||
/**
|
||||
* Handler for stages {@link com.facebook.react.surface.ReactStage}
|
||||
*/
|
||||
void onStage(int stage);
|
||||
|
||||
/**
|
||||
* Return native view for root
|
||||
*/
|
||||
ViewGroup getRootViewGroup();
|
||||
}
|
||||
Reference in New Issue
Block a user