React Native Application和Activity源码分析
基于V0.43.3版本 React Native Android端的ReactApplication和ReactActivity的实现原理. ReactApplication在Android端接入RN时,需要ReactApplication作为接口被Application实现. 从源码中可以看出ReactApplication只是提供了一个获取实现ReactNativeHost的接口. 这个类既然叫Host那么肯定承载了RN的实例和一些配置,可以通过下面的类图或源码看出它都有什么职责. 点击查看大图 从类图中可以看到RNHost中持有着Application的对象,这个很好理解,因为RN初始化一些部件或读取一些资源的时候肯定会需要用到Application. 而另外一个属性就是核心的ReactInstanceManager,RNHost类中的方法都是为InstanceManager服务的. R通过ReactInstanceManager管理配置负责Java和JS通讯的高层API类CatalystInstance,dev support的支持,并且绑定并同步与ReactRootView所在容器的声明周期. 下面简单看一下Host类对ReactInstanceManager配置和初始化的10个方法.
ReactActivityRN源码中有提供两个可以直接使用的Activity,分别是ReactActivity和ReactFragmentActivity. 他们两个的差别是分别继承自Activity和FragmentActivity. 对RN来说没有太大的区别,这里就只分析ReactActivity了. 并且可以通过对ReactActivity的分析,再结合RN的设计就可以自己封装出来类似ReactFragment之类的组件出来. 点击查看大图 从ReactActivity相关的类图可以看到它实现了两个接口,分别是用来将Android回退键点击事件代理给JS的DefaultHardwareBackBtnHandler 和 处理运行时权限授权申请和回调的PermissionAwareActivity. 除了这两个接口之外,ReactActivity还有一个ReactActivityDelegate的属性. 通过源码可以看到这个对象把ReactActivity的声明周期,事件和权限管理相关全部都同步并代理到自己内部. 通过getMainComponentName方法指定在JS中注册的主模块名称,并且在构造方法里对delegate对象进行初始化. 如果有特殊需求的话例如要向JS的主模块中传递一些数据等,可以选择复写createReactActivityDelegate方法,使用定制的ReactActivityDelegate子类进行初始化. protected ReactActivity() {
mDelegate = createReactActivityDelegate();
}
protected @Nullable String getMainComponentName() {
return null;
}
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this,getMainComponentName());
}
经过上面的分析,ReactActivity其实就是一个代理行为的空壳,真正的实现都在ReactActivityDelegate中. 接下来就进入类中看这个代理类究竟做了什么.首先看一下构造方法.由于ReactActivity和ReactFragmentActivity都使用了相同的Delegate类,所以提供了两个不同的构造接受Activity的实例和js端注册的模块名称. public ReactActivityDelegate(Activity activity,@Nullable String mainComponentName) {
mActivity = activity;
mMainComponentName = mainComponentName;
mFragmentActivity = null;
}
public ReactActivityDelegate(FragmentActivity fragmentActivity,@Nullable String mainComponentName) {
mFragmentActivity = fragmentActivity;
mMainComponentName = mainComponentName;
mActivity = null;
}
接下来看到有两个提供被代理方Context和Activity的方法,方便内部使用. private Context getContext() {
if (mActivity != null) {
return mActivity;
}
return Assertions.assertNotNull(mFragmentActivity);
}
private Activity getPlainActivity() {
return ((Activity) getContext());
}
往下看就能发现在上面讲ReactApplication的时候主要涉及到的两个类. Application只是提供了一个getReactNativeHost的方法,它本身并没有调用该方法对ReactInstanceManager进行初始化,上面一节有说过ReactInstanceManager是懒加载初始化的,从这看来ReactInstanceManager初始化的时机就是打开RN页面之后,在RN页面装载的过程中对其初始化. protected ReactNativeHost getReactNativeHost() {
return ((ReactApplication) getPlainActivity().getApplication()).getReactNativeHost();
}
public ReactInstanceManager getReactInstanceManager() {
return getReactNativeHost().getReactInstanceManager();
}
其他的方法例如 onResume,onPause,onDestroy,onActivityResult,onKeyUp,onBackPressed,onNewIntent,requestPermissions和onRequestPermissionsResult方法将声明周期同步到ReactInstanceManager中,点击/回退与devSupport事件相关联,动态权限申请和回调的管理起来,这里就不一一细说了. 除此之外onDestroy方法触发的时候还会根据情况将rootView从ReactInstanceManager对象中卸载掉. protected void onDestroy() {
if (mReactRootView != null) {
mReactRootView.unmountReactApplication();
mReactRootView = null;
}
if (getReactNativeHost().hasInstance()) {
getReactNativeHost().getReactInstanceManager().onHostDestroy(getPlainActivity());
}
}
单独分析一下onCreate方法,第一个大的if块是对DrawOverlays权限的判断. 因为从Android 6.0开始悬浮窗权限收紧,RN对该权限做了判断,如果没有DrawOverlays权限的话就跳转到系统设置页面动态申请. 有权限了之后就会调用loadApp方法,对RootView进行初始化. 最后初始化了一个双击R键的监听器,服务于Dev Support. protected void onCreate(Bundle savedInstanceState) {
boolean needsOverlayPermission = false;
if (getReactNativeHost().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Get permission to show redbox in dev builds.
if (!Settings.canDrawOverlays(getContext())) {
needsOverlayPermission = true;
Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,Uri.parse("package:" + getContext().getPackageName()));
FLog.w(ReactConstants.TAG,REDBOX_PERMISSION_MESSAGE);
Toast.makeText(getContext(),REDBOX_PERMISSION_MESSAGE,Toast.LENGTH_LONG).show();
((Activity) getContext()).startActivityForResult(serviceIntent,REQUEST_OVERLAY_PERMISSION_CODE);
}
}
if (mMainComponentName != null && !needsOverlayPermission) {
loadApp(mMainComponentName);
}
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
}
loadApp方法其实就是对RootView的初始化,并通过rootView的startReactApplication方法将其装载进ReactInstanceManager进行管理,与onDestroy方法中的unmountReactApplication相对应. 因为RootView就是一个view,将其装载进acitivty中就可以绘制出来. 后面会单独分析ReactRootView. protected ReactRootView createRootView() {
return new ReactRootView(getContext());
}
protected void loadApp(String appKey) {
if (mReactRootView != null) {
throw new IllegalStateException("Cannot loadApp while app is already running.");
}
mReactRootView = createRootView();
mReactRootView.startReactApplication(
getReactNativeHost().getReactInstanceManager(),appKey,getLaunchOptions());
getPlainActivity().setContentView(mReactRootView);
}
转载请注明出处:http://www.52php.cn/article/p-ebyyshjg-bpo.html (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |