在多个React Native活动实例之间共享单个ReactInstanceManager

7
我将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;
    }

我想在应用程序加载时解析一个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);

ReactInstanceManager应该在OnResume中设置一个新的activity:

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

    if (this.ReactInstanceManager != null) {
      this.ReactInstanceManager.onHostResume(this, this);
    }
  }

但是看起来它仍然在某个地方保留了对旧活动的引用。

所以,最终我做的是每次退出RN活动时销毁并重建ReactInstanceManager的实例。虽然这不是一个完美的选择,但它可以起作用。

我希望找到一种方法创建和持久化单个ReactInstanceManager实例,而不是在后台每次重新创建它。

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

你有什么解决方案吗?我也遇到了同样的问题。 - rupesh
我使用了MutableContextWrapper,请查看我的答案。 - Yury
2个回答

3
我找到了一个解决方案。 我使用MutableContextWrapper创建了初始ReactRootView。
ReactRootView reactRootView = new ReactRootView(new MutableContextWrapper(originActivity));

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

MutableContextWrapper contextWrapper = (MutableContextWrapper) reactRootView.getContext();
        contextWrapper.setBaseContext(currentActivity);

我可以预加载整个内容以便以后重复使用。我在一个Github问题中偶然发现了这个解决方案。希望有一种良好记录的方法来实现这一点。

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


太棒了,你提供了一个很好的解决方案!我们在共享ReactInstanceManager时遇到了问题。能否再详细说明一下?你是在哪里创建“initial ReactRootView”的?它们在哪里被重复使用?它们是独立的活动吗? - eugene
1
在 Github 上有很多这方面的示例。https://github.com/search?q=ReactRootView+MutableContextWrapper&type=code 如果您还有其他问题,请告诉我。 - Yury

0

你有ReactNativeHost,它持有ReactInstanceManager的实例

private ReactInstanceManager getReactInstanceManager() { return reactNativeHost.getReactInstanceManager(); }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接