ReactNative提供了ReactRootView,提供了集成RN View的途径。那么我们来看一下,如何通过ReactRootView,来封装项目中可以使用的Fragment。
深入ReactRootView源码
首先来看下
1 | public class ReactRootView extends SizeMonitoringFrameLayout |
SizeMonitoringFrameLayout类就是FrameLayout的再封装,对外提供了一个onSizeChange的监听方法.
1 | public class SizeMonitoringFrameLayout extends FrameLayout { |
再回来看ReactRootView内部,提供了startReactApplication()方法, 需要我们传入ReactInstanceManager和模块名等参数。
1 | public void startReactApplication(ReactInstanceManager reactInstanceManager, String moduleName) { |
startReactApplication内部主要是做了两件事,一件是在后台去创建React
Context,另一个是attachToReactInstanceManager(),那么另一个是attachToReactInstanceManager()做了什么呢?
1 | private void attachToReactInstanceManager() { |
ReactInstanceManager.attachRootView(ReactRootView)又做了什么呢?
1 | private final Set<ReactRootView> mAttachedRootViews = Collections.synchronizedSet( |
可以看到ReactInstanceManager内部维护了一个Set
1 | private void attachRootViewToInstance(final ReactRootView rootView) { |
ReactRootView的runApplication()方法我们就不再深入了,可以看一下它的注释说明
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.
可以看到,目的就是调到JS那里去启动React application。
而onAttachedToReactInstance()方法如下:
1 | public void onAttachedToReactInstance() { |
可以看到,目的就是将原生的View绑定上Js的Touch事件分发。至此,我们重新梳理下ReactRootView的逻辑,可以明确以下几点:
- ReactRootView继承自Android上FrameLayout,对外提供onSizeChange的接口。
- ReactRootView提供了startReactApplication方法,用于在后台去创建React
Context以及绑定ReactRootView到ReactApplication上。 - 绑定ReactRootView到ReactApplication上这一步做了两件事,一个是启动React application,一个是启用JSTouchDispatcher,用于View的JS事件分发。
封装ReactRootView
为了封装出我们需要的ReactNatvieFragment,我们需要对ReactRootView本身做一些封装,以实现怎么几个目的:
- 外部不需要处理ReactInstanceManager的逻辑
- 通过Bundle或者其他参数的形式,传入url,通知JS具体加载哪个页面
假设我们封装的一层View叫做RNBaseRootView,那么RNBaseRootView的构造函数可以是:
1 | public RNBaseRootView(Context context, String module, Bundle bundle) { |
为了抽离RNBaseRootView和ReactInstanceManager的逻辑,我们把ReactInstanceManager的相关处理逻辑委托给RNApiManager类,例如初始化ReactInstanceManage:
1 |
|
类似的,释放React Natvie的资源也可以放在里面
1 |
|
这样,在NBaseRootView的初始化方法里面,我们可以通过调用RNApiManager类,完成我们的初始化操作。
1 | private void initial() { |
接下来,ReactNativeFragment的实现就水到渠成了
1 | public class ReactNativeFragment extends Fragment { |
这样,我们就可以在工程中顺利的使用我们自己封装的ReactNativeFragment,可以很容易的嵌入到Tab中。