React Native 代码阅读(四):React Native 中的各种 Context

2019-02-18

前言

Context 在 Android 开发中是一个很重要的概念,用于提供各种上下文服务。在 React Native 中,它对 Context 进行了扩展。在本文中我们来梳理 React Native 中的各种 Context(ReactContext,ReactApplicationContext)。

继承关系

这几个 Context 类满足如下继承关系:

  • ContextWrapper
    • ReactContext
      • ReactApplicationContext

ReactContext

ReactContext 在 ContextWrapper 的基础上提供了哪些能力呢?

具体包括如下:

存放 CatalystInstance 实例引用:

  • CatalystInstance mCatalystInstance

方法三个线程的引用:

  • MessageQueueThread mUiMessageQueueThread
  • MessageQueueThread mNativeModulesMessageQueueThread
  • MessageQueueThread mJSMessageQueueThread

(从这里我们也能看出,React Native 在运行时启动了 3 条线程。)

存放原生模块异常处理器:

  • NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler

覆写了 getSystemService 的默认行为:

  • 修改了获取 Inflater 服务的逻辑
  • 在类中保存一个 Inflater 实例,而不是每次都创建一个新的

生命周期回调管理:

  • CopyOnWriteArraySet<LifecycleEventListener> mLifecycleEventListeners
  • CopyOnWriteArraySet<ActivityEventListener> mActivityEventListeners
  • 有两种生命周期:
    • LifecycleEventListener 接收 Resume、Pause、Destroy 事件
    • ActivityEventListener 接收 newIntent、Result

ReactApplicationContext

ReactApplicationContext 继承自 ReactContext,它在其基础上提供了哪些能力呢?

这个类啥能力也没提供,它唯一的作用就是在构造的时候获取 ApplicationContext。

/**
 * A context wrapper that always wraps Android Application {@link Context} and
 * {@link CatalystInstance} by extending {@link ReactContext}
 */
public class ReactApplicationContext extends ReactContext {
  // We want to wrap ApplicationContext, since there is no easy way to verify that application
  // context is passed as a param, we use {@link Context#getApplicationContext} to ensure that
  // the context we're wrapping is in fact an application context.
  public ReactApplicationContext(Context context) {
    super(context.getApplicationContext());
  }
}

ReactApplication

在 React Native 中还有一个类是 ReactApplication,千万不要把它跟 ReactApplicationContext 搞混了!

ReactApplication 是一个接口:

public interface ReactApplication {

  /**
   * Get the default {@link ReactNativeHost} for this app.
   */
  ReactNativeHost getReactNativeHost();
}

它的使用场景在创建 Application 时实现这个接口,用于提供 ReactNativeHost。与我们本文中讨论的内容完全不相关。因此我们不详细说它,只要别搞混就行。

创建

在 Android APP 中,如果不写任何代码,我们只能拿到 Android Context,如何转到 ReactContext 呢?

答案在 ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java 的 createReactContext 方法中:

在前面文章中我们梳理过,ReactInstanceManager 是通过一个 Builder 来构建的,构建时传入的一个参数是 Context,它存放在成员变量中:

  • Context mApplicationContext;

createReactContext 的具体逻辑在React Native 代码阅读(一):启动流程(Android)的 ReactContext 的创建与绑定一节中已做梳理,这里不再赘述。

其中有一行:

final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);

是用 mApplicationContext 创建了一个 ReactApplicationContext。

ReactInstanceManager 对 ReactApplicationContext 的使用

上一节中我们分析了 ReactContext 的创建过程。在本节中,我们分析 ReactInstanceManager 是如何使用 ReactApplicationContext 的。

首先,ReactApplicationContext 是在 runCreateReactContextOnNewThread 方法中被创建的。

在方法中首先调用 createReactContext 并创建一个局部变量:

final ReactApplicationContext reactApplicationContext =
    createReactContext(
        initParams.getJsExecutorFactory().create(),
        initParams.getJsBundleLoader());

之后调用:

setupReactContext(reactApplicationContext);

setupReactContext 方法对 reactApplicationContext 进行设置,我们来看它的内部实现:

首先将 reactApplicationContext 存放到 ReactInstanceManager 类的 mCurrentReactContext 成员中:

mCurrentReactContext = Assertions.assertNotNull(reactContext);

之后对 ReactContext 中存放的实例进行了一系列的初始化操作:

  • CatalystInstance 初始化
  • mDevSupportManager onNewReactContextCreated
  • mMemoryPressureRouter addMemoryPressureListener
  • 将所有 ReactRootView 附加到 catalystInstance 上
  • mReactInstanceEventListeners onReactContextInitialized 回调
  • 两条线程的优先级设置

小结

至此我们完成了 ReactNative 中 Context 的梳理。

在本文中,我们知道了 ReactContext 与 Android Context 的关系,以及 ReactContext 中提供了哪些服务。

同时我们也分析了 ReactInstanceManager 对 ReactApplicationContext 的使用。在 ReactInstanceManager 中,还有很多方法都需要传入 ReactContext 实例,供其他类使用,有了本文的知识这些都不在话下了。