RN安卓实现分析之ReactRootView的实现过程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RN安卓实现分析之ReactRootView的实现过程相关的知识,希望对你有一定的参考价值。

参考技术A 开篇之前日常安利
https://github.com/ddwhan0123/Useful-Open-Source-android (各种库的收纳,长期维护)

上一篇提到了入口类ReactActivity和他的代理实现类ReactActivityDelegate,这一次继续我们的分析之路

写着一片之前,没有看过任何其他兄弟对相关内容的分析,不是觉得自己牛逼。
是怕别人的思维影响到我的理解,如果讲得不对,欢迎指出!

上一篇的传送门 RN安卓实现分析之ReactActivity的前世今生

这是一个被 ReactActivity.setContentView(mReactRootView) 的UI控件,我们先来看下他的实现

既然是一个为了计算尺寸而自定义的的Layout那么一定会有 onMeasure(),onLayout(), 等方法

[图片上传失败...(image-3543be-1539429545128)]
首先获取了Mode类型,判断如果是 MeasureSpec.AT_MOST 或者 MeasureSpec.UNSPECIFIED 就对子控件进行循环计算复制给 width 变量,如果不是的话直接调用 MeasureSpec.getSize() 方法进行赋值。

高度同上,我们就得到了 2个具体的宽高值。然后调用 setMeasuredDimension(width, height); ,设置当前View的大小。

[图片上传失败...(image-9f6f59-1539429545128)]

计算完把ReactRootView的类变量mWasMeasured设置为true,表示控件已经计算过了!

经过判断决定是刷新位置信息还是构建ReactInstanceManager实例
在mReactInstanceManager为null时,enableLayoutCalculation()方法直接返回,否则会对当前mReactInstanceManager对象的ReactContext进行一轮设置。

那么mReactInstanceManager又是在哪初始化的呢?
[图片上传失败...(image-1a33ab-1539429545128)]
这个就是我们在ReactActivity调用的那个方法,传入的是

所携带的mReactNativeHost里的mReactInstanceManager。这个对象一定不会为空因为,该对象为空的话他会创建个新的!

所以startReactApplication方法后执行的方法为其内部的 attachToReactInstanceManager();

该方法把 mIsAttachedToInstance 值改为了true,然后添加了一个自定义 OnGlobalLayoutListener

无论怎么走都会有一个私有类 CustomGlobalLayoutListener 的实例,它实现了 ViewTreeObserver.OnGlobalLayoutListener 接口

CustomGlobalLayoutListener有点长,我们一步步看

构造函数会给创建小方块以及给键盘最小高度赋值

可视回调触发后,分别检验键盘,横竖屏和设备可用尺寸的变化

[图片上传失败...(image-d27922-1539429545128)]

各种噼里啪啦的计算后把结果用 sendEvent(String eventName, @Nullable WritableMap params) 方法进行传递

sendEvent方法会最终会调用 mReactInstanceManager 的 emit(String eventName, @Nullable Object data); 方法把结果传给JS部分,返回键啥的也是走emit方法

旋转方法checkForDeviceOrientationChanges()最终会传递一个key为namedOrientationDidChange的事件

检测屏幕尺寸的方法 checkForDeviceDimensionsChanges() 最终会传递一个key为didUpdateDimensions的事件

虽然计算场景有所差异 但是最终都是调用emit

在绘制的时候调用过 updateRootLayoutSpecs() 也就是当内容发现变化的时候由他来实现真实当更新操作

[图片上传失败...(image-629dfb-1539429545128)]

首先拿到上下文对象 ReactContext,因为它是一个 volatile 的变量所以是时不时会刷新一下值,但是不会为空

然后就是handler的UI操作了
调用的是 com.facebook.react.uimanager 下面的UIManagerModule updateRootLayoutSpecs(int rootViewTag, int widthMeasureSpec, int heightMeasureSpec) 方法
传入一个Tag和我们计算的结果进行UI操作(这部分怎么实现的之后再找时间分析)

那么看下这个Tag ,找了一圈是UIManagerModule addRootView( final T rootView) 方法的返回值,也就是拿这个ReactRootView类里的Tag变量和当前业务UIManagerModule类中rootView的Tag做了关联

有启动就一定有销毁,不然强行等GC么? unmountReactApplication()

官方建议在外部Activity或者容器Fragment的 onDestroy()/onDestroyView()
方法调用即可

一开始有提到这个容器控件还传递子控件的手势,在 onChildStartedNativeGesture() 方法把子控件的事件用 UIManagerModule 的 mEventDispatcher 属性调用JS事件分发类 JSTouchDispatcher 的 onChildStartedNativeGesture(MotionEvent androidEvent, EventDispatcher eventDispatcher) 方法把事件传递给JS逻辑处理

[图片上传失败...(image-a7d9ae-1539429545128)]

在好几个容器控件都有用到,该实现
[图片上传失败...(image-622f7f-1539429545128)]

主要流程的方法都介绍完整了,这一篇还是比较细的,当然还有几个自定义入口的方法没介绍,但是并不影响你对 ReactRootView 的理解

ReactRootView主要的功能是提供强大的控件能力和事件传递

startReactApplication 方法调用后绑定上 OnGlobalLayoutListener 监听
然后对屏幕,页面旋转,键盘相关进行了着重计算处理。
onMeasure() 方法计算完结果通过 UIManagerModule 对UI进行渲染么不是本身自身实现绘制操作。
unmountReactApplication() 方法可以卸载不用的视图对象,以防内存泄漏
onChildStartedNativeGesture(MotionEvent androidEvent) 方法把事件传递给RTC控件处理业务逻辑

如果有不对的欢迎留言纠正!

插一段广告

蔚来汽车
上海 安亭/徐家汇/漕河泾 (安亭有班车)
收Android/ios/.Net/Java/Vue/RN开发
标准五险一金(不避税)
不强制加班,弹性工作

有意向的可以加我微信,必须注明来意

以上是关于RN安卓实现分析之ReactRootView的实现过程的主要内容,如果未能解决你的问题,请参考以下文章

RN与现有的原生app集成

RN安卓原生模块

RN - 封装Android原生WebView组件,实现JS获取原生消息回调及JS控制native组件

React Native 安卓开发----第三方框架的引用之React-native-Swiper框架实现欢迎页第五篇

MySQL分析函数实现

React Native组件之BackAndroid !安卓手机的物理返回键的使用