在React本机活动的多个实例之间共享一个ReactInstanceManager

Yur*_*ury 5 android react-native

我将React Native集成到本机Android应用程序中,并从本机代码创建React Native活动的新实例.

以下是包装ReactInstanceManager的类的代码:

public class ReactNativeInstanceWrapper
{

private static ReactNativeInstanceWrapper instance = new ReactNativeInstanceWrapper();

public static ReactNativeInstanceWrapper getInstance() {
        return instance;
    }

    private ReactInstanceManager reactInstanceManager;

    public ReactInstanceManager GetReactInstanceManager()
    {
        return reactInstanceManager;
    }

    public ReactInstanceManager Rebuild(Application application)
    {
        Boolean isDebugBuild = AppBuildType.IsBuildConfigDebug(application.getBaseContext());

        reactInstanceManager = null;
        synchronized (this) {
            reactInstanceManager = ReactInstanceManager.builder()
                    .setApplication(application)
                    .setBundleAssetName("index.android.bundle")
                    .setJSMainModuleName("index.android")
                    .addPackage(new MainReactPackage())
                    .addPackage(new ReactIntegrationPackage())
                    .addPackage(new PickerPackage())
                    .addPackage(new LinearGradientPackage())
                    .setUseDeveloperSupport(isDebugBuild)
                    .setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
                    .build();
        }

        if (!reactInstanceManager.hasStartedCreatingInitialContext())
        {
            reactInstanceManager.createReactContextInBackground();
        }

        return reactInstanceManager;
    }
Run Code Online (Sandbox Code Playgroud)

我想在应用程序加载时解析一个js包并缓存它,这使得加载React Native的速度更快.问题是它看起来像在多个活动之间共享ReactInstanceManager导致一些问题.

例如,在一种情况下,如果我在我的某个活动中打开一个共享表,而不是回到我的RN活动并关闭它,我就无法在新的RN活动中打开一个对话框.它抛出一个WindowManager $ BadTokenException,这可能意味着它试图将它附加到一个不存在的活动.

在RN活动中,以下是我在OnCreate中创建ReactRootView的方法:

  this.ReactRootView = new ReactRootView(this);
    setContentView(this.ReactRootView);

    ReactNativeInstanceWrapper reactNativeInstanceWrapper = ReactNativeInstanceWrapper.getInstance();
    this.ReactInstanceManager = reactNativeInstanceWrapper.GetReactInstanceManager();
    if (this.ReactInstanceManager == null) {
      this.ReactInstanceManager = ReactNativeInstanceWrapper.getInstance().Rebuild(getApplication());
    }
    this.ReactRootView.startReactApplication(this.ReactInstanceManager, reactNativeComponent, initialProps);
Run Code Online (Sandbox Code Playgroud)

ReactInstanceManager应该在OnResume中设置一个新活动:

  @Override
  protected void onResume()
  {
    super.onResume();

    if (this.ReactInstanceManager != null) {
      this.ReactInstanceManager.onHostResume(this, this);
    }
  }
Run Code Online (Sandbox Code Playgroud)

但看起来它仍然会在某处保留对旧活动的引用.

所以,我最终做的就是每次离开RN活动时都会破坏并重建ReactInstanceManager的实例.它不是一个完美的选择,但它的工作原理.

我想找到一种方法来创建和持久化ReactInstanceManager的单个实例,如果每次在后台重新创建它.

  • react-native -v:0.42.3
  • node -v:v6.11.0
  • npm -v:5.2.0
  • 平台:Android

Yur*_*ury 3

这是我找到的解决方案。

我使用 MutableContextWrapper 创建初始 ReactRootView。

ReactRootView reactRootView = new ReactRootView(new MutableContextWrapper(originActivity));
Run Code Online (Sandbox Code Playgroud)

它允许我在 OnCreate 中用新的上下文替换它

MutableContextWrapper contextWrapper = (MutableContextWrapper) reactRootView.getContext();
        contextWrapper.setBaseContext(currentActivity);
Run Code Online (Sandbox Code Playgroud)

这样我就可以预加载整个内容并在以后重用。我在 github issues 中偶然发现了这个解决方案。我希望有一个有据可查的方法来做到这一点。

在旧版本的 React Native 中,旧的模态对话框引用曾经也存在问题,但现在已修复。