React Native是怎么在Android上跑起来的

前端之家收集整理的这篇文章主要介绍了React Native是怎么在Android上跑起来的前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

(源码版本:0.34,新版本(0.48)基本流程是不变的,建议跟着源码看看,哪个版本的倒影响不大)
这篇简单刨析一下React Native是怎么在Android上跑起来的,会从下面几个方面说说。

  • 启动流程
  • 通信机制
  • 事件驱动
  • 渲染原理
  • 脚本执行

启动流程

React NativeAndroid上启动是从ReactRootView.startReactApplication触发的,而ReactRootView是继承FrameLayout的,所以React NativeAndroid的操作都是在这个View中进行的。

  1. startReactApplication(ReactInstanceManager reactInstanceManager,String moduleName,@Nullable Bundle launchOptions)

这个方法参数第一个ReactInstanceManager,实现是XReactInstanceManagerImpl,可以理解在应用层对RN的配置都是对这个类操作实现的。moduleName是要启动的RNComponentname,是在jsAppRegistry.registerComponent('xxx',() => App);定义的。最后的launchOptions是传过去的参数,可以在jsComponentprops获取

下一步到了mReactInstanceManager.createReactContextInBackground();是在后台线程中创建RNReactContext上下文对象,然后到

  1. //JavaScriptExecutor 默认就是jsc,如果的debug在chrome上时候,就是v8。
  2. //JSBundleLoader 有AssetLoader FileLoader CachedBundleFromNetworkLoader RemoteDebuggerBundleLoader 从不同的地方加载bundle
  3. private void recreateReactContextInBackground(
  4. JavaScriptExecutor.Factory jsExecutorFactory,JSBundleLoader jsBundleLoader) {
  5. UiThreadUtil.assertOnUiThread();
  6.  
  7. ReactContextInitParams initParams =
  8. new ReactContextInitParams(jsExecutorFactory,jsBundleLoader);
  9. if (mReactContextInitAsyncTask == null) {
  10. // No background task to create react context is currently running,create and execute one.
  11. mReactContextInitAsyncTask = new ReactContextInitAsyncTask();
  12. mReactContextInitAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,initParams);
  13. } else {
  14. // Background task is currently running,queue up most recent init params to recreate context
  15. // once task completes.
  16. mPendingReactContextInitParams = initParams;
  17. }
  18. }

主要的创建工作就转移到了ReactContextInitAsyncTask这个AsyncTask里面,

  1. @Override
  2. protected Result<ReactApplicationContext> doInBackground(ReactContextInitParams... params) {
  3. ....
  4. return Result.of(createReactContext(jsExecutor,params[0].getJsBundleLoader()));
  5. ....
  6. }
  7.  
  8. private ReactApplicationContext createReactContext(
  9. JavaScriptExecutor jsExecutor,JSBundleLoader jsBundleLoader) {
  10. ...
  11. NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder();//NativeModule的注册
  12. JavaScriptModuleRegistry.Builder jsModulesBuilder = new JavaScriptModuleRegistry.Builder();//jsModules的注册
  13. ...打包定义的各种modules到上面的注册表...
  14.  
  15. //创建关键的CatalystInstanceImpl
  16. CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
  17. ...
  18. catalystInstance = catalystInstanceBuilder.build();
  19. ....
  20. //扔到js线程中加载js脚本
  21. catalystInstance.getReactQueueConfiguration().getJSQueueThread().callOnQueue(
  22. new Callable<Void>() {
  23. @Override
  24. public Void call() throws Exception {
  25. //让reactContext持有catalystInstance
  26. reactContext.initializeWithInstance(catalystInstance);
  27. ...
  28. catalystInstance.runJSBundle();
  29. return null;
  30. }
  31. }).get();
  32. }

CatalystInstanceImpl的构造函数中有

  1. ...
  2. //native C++方法,用来初始化JNI相关状态然后返回mHybridData。具体在 OnLoad.cpp 的 JSCJavaScriptExecutorHolder 类中
  3. mHybridData = initHybrid();
  4. ...
  5. //初始化线程环境,包括和主线程绑定,JS线程,Native线程创建。
  6. mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
  7. ReactQueueConfigurationSpec,new NativeExceptionHandler());
  8. ...
  9. initializeBridge(
  10. new BridgeCallback(this),//CatalystInstanceImpl内部类,用于native对java的一些回调
  11. jsExecutor,//jsc
  12. mReactQueueConfiguration.getJSQueueThread(),//js线程队列
  13. mReactQueueConfiguration.getNativeModulesQueueThread(),//native线程队列
  14. mJavaRegistry.getModuleRegistryHolder(this));//nativemodules注册
  15. mMainExecutorToken = getMainExecutorToken();//貌似是用于切换jsExecutor的标记,后面版本删掉了。

然后就进入到了cpp层的CatalystInstanceImpl.cppinitializeBridge方法

  1. void CatalystInstanceImpl::initializeBridge(
  2. jni::alias_ref<ReactCallback::javaobject> callback,// This executor is actually a factory holder.
  3. JavaScriptExecutorHolder* jseh,jni::alias_ref<JavaMessageQueueThread::javaobject> jsQueue,jni::alias_ref<JavaMessageQueueThread::javaobject> moduleQueue,ModuleRegistryHolder* mrh) {
  4.  
  5. instance_->initializeBridge(folly::make_unique<JInstanceCallback>(callback),jseh->getExecutorFactory(),folly::make_unique<JMessageQueueThread>(jsQueue),folly::make_unique<JMessageQueueThread>(moduleQueue),mrh->getModuleRegistry());
  6. }

然后有委托给了Instance.cppinitializeBridge方法

  1. void Instance::initializeBridge(
  2. std::unique_ptr<InstanceCallback> callback,std::shared_ptr<JSExecutorFactory> jsef,std::shared_ptr<MessageQueueThread> jsQueue,std::unique_ptr<MessageQueueThread> nativeQueue,std::shared_ptr<ModuleRegistry> moduleRegistry) {
  3. callback_ = std::move(callback);
  4.  
  5. //在js线程中包装nativeQueue和创建nativeToJsBridge_,后者在双向bridge起作用,不要仅仅看名字,内部还有一个JsToNativeBridge
  6. jsQueue->runOnQueueSync(
  7. [this,&jsef,moduleRegistry,jsQueue,nativeQueue=folly::makeMoveWrapper(std::move(nativeQueue))] () mutable {
  8. nativeToJsBridge_ = folly::make_unique<NativeToJsBridge>(
  9. jsef.get(),nativeQueue.move(),callback_);
  10. });
  11. CHECK(nativeToJsBridge_);
  12. }

到这就看没了,再回到上面的catalystInstance.runJSBundle();FileLoader为例,最终走到native void loadScriptFromFile(String fileName,String sourceURL);进入CatalystInstanceImpl.cpp进而委托给Instance.cpp。预警。。下面是一大片的cpp代码

  1. void Instance::loadScriptFromFile(const std::string& filename,const std::string& sourceURL) {
  2. ...检测文件合法性等...
  3. loadScriptFromString(std::move(buf),sourceURL);
  4. }
  5.  
  6. void Instance::loadScriptFromString(std::unique_ptr<const JSBigString> string,std::string sourceURL) {
  7. callback_->incrementPendingJSCalls();//这个callback就是java层的CatalystInstanceImpl的BridgeCallback这个内部类。
  8. ...
  9. nativeToJsBridge_->loadApplicationScript(std::move(string),std::move(sourceURL));
  10. }
  11.  
  12. void NativeToJsBridge::loadApplicationScript(std::unique_ptr<const JSBigString> script,std::string sourceURL) {
  13. m_mainExecutor->loadApplicationScript(std::move(script),std::move(sourceURL));
  14. }
  15.  
  16. void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> script,std::string sourceURL) throw(JSException) {
  17. ...
  18. //使用webkit JSC去真正解释执行Javascript了!
  19. evaluateScript(m_context,jsScript,jsSourceURL);
  20. //绑定桥,核心是通过getGlobalObject将JS与C++通过webkit JSC bind
  21. bindBridge();
  22. flush();
  23. }
  24.  
  25. void JSCExecutor::bindBridge() throw(JSException) {
  26. ...下面都是通过jsc 获取js的一下属性方法...
  27. auto global = Object::getGlobalObject(m_context);
  28. auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
  29. ...
  30. auto batchedBridge = batchedBridgeValue.asObject();
  31. m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
  32. m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue").asObject();
  33. //这个比较重要 获取MessageQueue.js的flushedQueue 下面就用到
  34. m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
  35. }
  36.  
  37. //这个下面js->native的时候还会提到
  38. void JSCExecutor::flush() {
  39. ...真的烦,绕来绕去 m_flushedQueueJS看上面
  40. callNativeModules(m_flushedQueueJS->callAsFunction({}));
  41. }
  42.  
  43. void JSCExecutor::callNativeModules(Value&& value) {
  44. ...
  45. try {
  46. auto calls = value.toJSONString();
  47. //class JsToNativeBridge : public react::ExecutorDelegate
  48. m_delegate->callNativeModules(*this,std::move(calls),true);
  49. } catch (...) {
  50. ...
  51. }
  52. }
  53.  
  54. void callNativeModules(
  55. JSExecutor& executor,std::string callJSON,bool isEndOfBatch) override {
  56. ExecutorToken token = m_nativeToJs->getTokenForExecutor(executor);
  57. m_nativeQueue->runOnQueue([this,token,callJSON=std::move(callJSON),isEndOfBatch] {
  58. for (auto& call : react::parseMethodCalls(callJSON)) {
  59. //快完了 这个是ModuleRegistry.cpp 是在initializeBridge间接创建包装nativemodule的
  60. m_registry->callNativeMethod(
  61. token,call.moduleId,call.methodId,std::move(call.arguments),call.callId);
  62. }
  63. if (isEndOfBatch) {
  64. //又见到了这个callback
  65. m_callback->onBatchComplete();
  66. m_callback->decrementPendingJSCalls();
  67. }
  68. });
  69. }
  70.  
  71. void ModuleRegistry::callNativeMethod(ExecutorToken token,unsigned int moduleId,unsigned int methodId,folly::dynamic&& params,int callId) {
  72. ...
  73.  
  74. modules_[moduleId]->invoke(token,methodId,std::move(params));
  75.  
  76. }

看到最后一句就是要去调用nativeModule里面的方法了,具体在ModuleRegistryHolder.cppJavaNativeModule类和NewJavaNativeModule类,对应JavaJavaModuleWrapper.java,就是jni调用

说到这里,现在只完成了bridge环境的初步搭建,把jsbundle扔到jsc里面,还没真正拉起React Native应用。还是回到上面那个AsyncTaskonPostExecute方法。看看执行完这么一大堆准备代码之后,是怎么拉起来整个应用的。

  1. @Override
  2. protected void onPostExecute(Result<ReactApplicationContext> result) {
  3. ....
  4. setupReactContext(result.get());
  5. }
  6.  
  7. private void setupReactContext(ReactApplicationContext reactContext) {
  8. ...各种listener回调,通知birdge就绪,reactContext创建完成
  9. for (ReactRootView rootView : mAttachedRootViews) {
  10. attachMeasuredRootViewToInstance(rootView,catalystInstance);
  11. }
  12. ...各种listener回调,通知birdge就绪,reactContext创建完成
  13. }
  14.  
  15.  
  16. private void attachMeasuredRootViewToInstance(ReactRootView rootView,CatalystInstance catalystInstance) {
  17. ....
  18. UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
  19. int rootTag = uiManagerModule.addMeasuredRootView(rootView);
  20. rootView.setRootViewTag(rootTag);
  21. @Nullable Bundle launchOptions = rootView.getLaunchOptions();
  22. WritableMap initialProps = Arguments.makeNativeMap(launchOptions);
  23. String jsAppModuleName = rootView.getJSModuleName();
  24.  
  25. WritableNativeMap appParams = new WritableNativeMap();
  26. appParams.putDouble("rootTag",rootTag);
  27. appParams.putMap("initialProps",initialProps);
  28. //真正拉起react native 的地方
  29. catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName,appParams);
  30. }

再来详细说一下最后一句,(大量代码预警)

  1. @Override
  2. public <T extends JavaScriptModule> T getJSModule(ExecutorToken executorToken,Class<T> jsInterface) {
  3. //进入JSModuleRegistry中
  4. return Assertions.assertNotNull(mJSModuleRegistry)
  5. .getJavaScriptModule(this,executorToken,jsInterface);
  6. }
  7.  
  8. //JavaScriptModuleRegistry.java
  9. public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
  10. CatalystInstance instance,ExecutorToken executorToken,Class<T> moduleInterface) {
  11. HashMap<Class<? extends JavaScriptModule>,JavaScriptModule> instancesForContext =
  12. mModuleInstances.get(executorToken);
  13. if (instancesForContext == null) {
  14. instancesForContext = new HashMap<>();
  15. //缓存一下 方便后面再使用
  16. mModuleInstances.put(executorToken,instancesForContext);
  17. }
  18. JavaScriptModule module = instancesForContext.get(moduleInterface);
  19. if (module != null) {
  20. //命中缓存 直接返回
  21. return (T) module;
  22. }
  23. JavaScriptModuleRegistration registration =
  24. ...
  25. //很明显 动态代理 重点关注JavaScriptModuleInvocationHandler的invoke方法
  26. JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
  27. moduleInterface.getClassLoader(),new Class[]{moduleInterface},new JavaScriptModuleInvocationHandler(executorToken,instance,registration));
  28. instancesForContext.put(moduleInterface,interfaceProxy);
  29. return (T) interfaceProxy;
  30. }
  31.  
  32. @Override
  33. public @Nullable Object invoke(Object proxy,Method method,@Nullable Object[] args) throws Throwable {
  34. ....
  35. //又跑到了CatalystInstanceImpl.java中。。。然后又桥接到了CatalystInstanceImpl.cpp中,同样会调用instance的对应方法,直接看吧
  36. mCatalystInstance.callFunction(
  37. executorToken,mModuleRegistration.getName(),method.getName(),jsArgs
  38. );
  39. return null;
  40. }
  41.  
  42. void Instance::callJSFunction(ExecutorToken token,std::string&& module,std::string&& method,folly::dynamic&& params) {
  43. callback_->incrementPendingJSCalls();//这个回调不多说
  44. //....接着跟吧
  45. nativeToJsBridge_->callFunction(token,std::move(module),std::move(method),std::move(params));
  46. }
  47.  
  48. //又会进入executor->callFunction(module,method,arguments);
  49. void JSCExecutor::callFunction(const std::string& moduleId,const std::string& methodId,const folly::dynamic& arguments) {
  50. ....
  51. auto result = [&] {
  52. try {
  53. //被桥接到MessageQueue.js的callFunctionReturnFlushedQueue方法
  54. return m_callFunctionReturnFlushedQueueJS->callAsFunction({
  55. Value(m_context,String::createExpectingAscii(moduleId)),Value(m_context,String::createExpectingAscii(methodId)),Value::fromDynamic(m_context,std::move(arguments))
  56. });
  57. } catch (...) {
  58. std::throw_with_nested(
  59. std::runtime_error("Error calling function: " + moduleId + ":" + methodId));
  60. }
  61. }();
  62. //顺便还会调用一下native的 这个会在后面再说一下
  63. callNativeModules(std::move(result));
  64. }
  65.  
  66. callFunctionReturnFlushedQueue(module,args) {
  67. guard(() => {
  68. //执行js的function
  69. this.__callFunction(module,args);
  70. this.__callImmediates();
  71. });
  72. //取出积攒在queue中的action返回给上面的,最终在java中执行
  73. return this.flushedQueue();
  74. }
  75.  
  76. __callFunction(module: string,method: string,args: any) {
  77. ...
  78. //根据module名,方法名和参数执行js方法
  79. const result = moduleMethods[method].apply(moduleMethods,args);
  80. return result;
  81. }
  82. //那什么时候把js的module注册到moduleMethods中呢
  83. //AppRegistry.js
  84. BatchedBridge.registerCallableModule(
  85. 'AppRegistry',AppRegistry
  86. );
  87. //BatchedBridge是啥?
  88. const BatchedBridge = new MessageQueue(
  89. () => global.__fbBatchedBridgeConfig,serializeNativeParams
  90. );
  91. registerCallableModule(name,methods) {
  92. this._callableModules[name] = methods;
  93. }

这里就执行了AppRegistry.js的的runApplication方法

  1. runApplication: function(appKey: string,appParameters: any): void {
  2. ...
  3. runnables[appKey].run(appParameters);
  4. },//而runnables是在什么时候被添加的??下面
  5.  
  6. registerComponent: function(appKey: string,getComponentFunc: ComponentProvider): string {
  7. runnables[appKey] = {
  8. run: (appParameters) =>
  9. renderApplication(getComponentFunc(),appParameters.initialProps,appParameters.rootTag)
  10. };
  11. return appKey;
  12. },//而registerComponent什么时候被调用的就不用说了吧

到此真正执行到了js脚本,开始执行Component的逻辑渲染,最终映射到NativeView上。后面会再详细说渲染的原理。同时会发现在 JSCExecutor 中每次 Java 调用 JS 之后会进行 Java 端的一个回调(从 JS 层的 MessageQueue.js 中获得累积的 JS Call)。

通信机制

上面关于java->js已经体现的差不多了,实质就是 JavaJS 端都准备好一个 Module 映射表,然后当 Java调用 JS 代码Java 端通过查表动态代理创建一个与 JS 对应的 Module 对象,当调用这个 Module方法时 Java 端通过动态代理的 invoke 方法触发 C++ 层,层层调用后通过 JSCExecutor 执行 JS 端队列中的映射查表找到 JS方法进行调用js->java调用会在渲染原理里面提到。

简单画了个图

渲染原理

现在以一个Image如何渲染到Native为例,说一下简单的流程。
当执行js的脚本时候,是不知道nativeModule注册表的,因为nativeModule注册表只保存在javacpp端,并没有直接传递到js端。所有当执行到

  1. import {
  2. Image,} from 'react-native';

这时候js并不知道Image是什么,然后看一下代码

  1. const ReactNative = {
  2. ...
  3. get Image() { return require('Image'); },...
  4. }
  5. ...
  6. module.exports = ReactNative;
  7.  
  8. //Image.android.js
  9.  
  10. var NativeModules = require('NativeModules');
  11.  
  12. //NativeModules.js
  13.  
  14. const NativeModules = {};
  15. Object.keys(RemoteModules).forEach((moduleName) => {
  16. Object.defineProperty(NativeModules,moduleName,{
  17. configurable: true,enumerable: true,get: () => {
  18. let module = RemoteModules[moduleName];
  19. if (module && typeof module.moduleID === 'number' && global.nativeRequireModuleConfig) {
  20. //nativeRequireModuleConfig映射到JSCExecutor.cpp
  21. const config = global.nativeRequireModuleConfig(moduleName);
  22. module = config && BatchedBridge.processModuleConfig(config,module.moduleID);
  23. RemoteModules[moduleName] = module;
  24. }
  25. Object.defineProperty(NativeModules,{
  26. configurable: true,value: module,});
  27. return module;
  28. },});
  29. });
  30.  
  31. module.exports = NativeModules;
  32.  
  33. //cpp
  34. JSCExecutor::nativeRequireModuleConfig->JsToNativeBridge::getModuleConfig->ModuleRegistry::getConfig
  35.  
  36. folly::dynamic ModuleRegistry::getConfig(const std::string& name) {
  37.  
  38. ...
  39. NativeModule* module = modules_[it->second].get();
  40. ...
  41. //最终反射调用JavaModuleWrapper.java的getConstants
  42. folly::dynamic constants = module->getConstants();
  43. ...
  44. //最终反射调用JavaModuleWrapper.java的getMethods
  45. //返回对应module中所有@ReactMethod注解的方法
  46. std::vector<MethodDescriptor> methods = module->getMethods();
  47.  
  48. //modules_在哪赋值?
  49. //ModuleRegistryHolder.cpp构造函数,这个类上面有提到,回去看看
  50. //registry_ = std::make_shared<ModuleRegistry>(std::move(modules));
  51. }

然后返回到NativeModules.js中,BatchedBridge.processModuleConfig
->_genModule->_genMethod。进一步处理一下。所以到现在,js获取到了Image这个module中所有方法属性

然后当调用Image中相关方法时候,其实就是调用上面_genMethod中的方法,在这个方法中,分promisesync其他调用类型,最终都是调用

  1. __nativeCall(module,params,onFail,onSucc) {
  2. ...
  3. this._queue[MODULE_IDS].push(module);
  4. this._queue[METHOD_IDS].push(method);
  5. this._queue[PARAMS].push(preparedParams);
  6. ...
  7. //如果5ms内有多个方法调用就先待在队列里防止过高频率,否则调用C++的nativeFlushQueueImmediate方法
  8. if (global.nativeFlushQueueImmediate &&
  9. now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS) {
  10. global.nativeFlushQueueImmediate(this._queue);
  11. this._queue = [[],[],this._callID];
  12. this._lastFlush = now;
  13. }
  14. }

上面把MODULE_IDSMETHOD_IDSPARAMS放到queue中,等待java调用,至于什么时候会触发java调用和为什么要这么设计,会在下面的事件驱动解释。调用JSCExecutor::flush()。还有就是直接调用cppnativeFlushQueueImmediate,最终这两种方式都是调用callNativeModules,这个上面也说了,不再赘述啦。

下面再说一下Nativeview创建过程,这个过程中Viewtag标记View的作用,从java拉起React NativeattachMeasuredRootViewToInstance方法中可以看到

  1. appParams.putDouble("rootTag",initialProps);

rootTag通过bridge带到了js端,js执行React逻辑后,要创建一个NativeView,同时也把这个rootTag带到java层,让java层知道,创建完一个View添加到哪个根布局上。

这个rootTag生成是有规则的,在UIManagerModule.addMeasuredRootView的时候会生成RootViewTag

  1. final int tag = mNextRootViewTag;//默认是1
  2. mNextRootViewTag += ROOT_VIEW_TAG_INCREMENT;//10

也就是默认的rootTag是1,后面每多创建一个+10,也就是类似1,11,21这样都是根布局的tag

再通过这个rootTagjs的传递简单说一下React.js的创建组件逻辑。从前面可以知道,拉起js后执行AppRegistry.js ::runApplication,进而执行到了renderApplication(getComponentFunc(),appParameters.rootTag)这个方法。这里可以看到从java传过来的两个参数,其中一个就是rootTag,这里默认就一个根布局,这里的rootTag==1,进而到了renderApplication.js

  1. ReactNative.render(
  2. <AppContainer> <RootComponent {...initialProps} rootTag={rootTag} /> </AppContainer>,rootTag );

这里的AppContainer也是一个组件,是包裹在根布局的外面,用于debug的红盒等工具布局。再到了

  1. //ReactNative.js
  2. var render = function (element,mountInto,callback) {
  3. return ReactNativeMount.renderComponent(element,callback);
  4. };

这里面的逻辑快到React的一些处理,这里不多赘述,其实还有很多关于React Native的处理,暂时忽略,分支太多太繁琐。简单说一下React Native组件可以分为两种

元组件:框架内置的,可以直接使用的组件。例如:View、Image等。它在React Native中用ReactNativeBaseComponent来描述。
复合组件:用户封装的组件,一般可以通过React.createClass()来构建,提供render()方法来返回渲染目标。它在React Native中用ReactCompositeComponent来描述。

具体组合的逻辑基本都在上面连个类里面。下面来到ReactNativeBaseComponent.jsmountComponent,根据上面的提示是可以跟到这里的。只挑简单的看,看这个方法里面的

  1. var tag = ReactNativeTagHandles.allocateTag();//给每个view生成一个唯一的tag
  2. ...
  3. UIManager.createView(tag,this.viewConfig.uiViewClassName,nativeTopRootTag,updatePayload);
  4.  
  5. //ReactNativeTagHandles.js
  6. allocateTag: function () {
  7. //排除已经给分配给rootTag的 类似1,11,21
  8. //下面的就是简单的自增,初始化是1
  9. while (this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount)) {
  10. ReactNativeTagHandles.tagCount++;
  11. }
  12. var tag = ReactNativeTagHandles.tagCount;
  13. ReactNativeTagHandles.tagCount++;
  14. return tag;
  15. },

看名字也知道这里就到了创建View的地方,还有另外两个方法和这个差不多的,用来操作View,分别的updateViewmanageChildrenUIManager通过bridge可以映射到javaUIManagerModule.java,可以在duiyiing这个类里面找到对应的用@ReactMethod注解的方法,这个注解是干啥的,看上面有提到。这里只看createView

  1. @ReactMethod
  2. //创建view的tag,对应native的组件类名,要加入的根布局tag,创建view需要的参数
  3. public void createView(int tag,String className,int rootViewTag,ReadableMap props) {
  4. mUIImplementation.createView(tag,className,rootViewTag,props);
  5. }

UIImplementation.java中把要创建的view包装成CSSNode,用于后面的在CssLayout中布局。然后会包装成一个CreateViewOperation加入到UIViewOperationQueue.javaArrayDeque<UIOperation> mNonBatchedOperations这个队列中。最后还是通过GuardedChoreographerFrameCallback这个垂直同步的回调中出队,执行。关于事件驱动还是看下面。还有 updateview setchilderen就不说了,很复杂。

事件驱动

在说React Native的事件驱动之前,先看一下这几篇
Android图形显示系统(一)
React Native 分析(二)事件驱动
Android中的SurfaceFlinger和Choreographer
了解一下垂直同步和在Android上的Choreographer,正因为React Native使用了Choreographer这个类,而这个类是在4.1加入的,所以RN-Android的最低兼容是4.1,而weex是最低兼容到4.0,是在4.0使用了handler延时来模拟垂直同步的效果。当然这也是老版本Android的做法。这也是为啥总是吐槽Android显得很卡,当然在5.0又引入了renderThread就更上了一个台阶,还有Android属性动画也是靠这个驱动的。

下面简单贴一下Choreographer的注释,看看为啥跨平台的框架都会用到这个类

However,there are a few cases where you might want to use the functions of thechoreographer directly in your application. Here are some examples.

  • If your application does its rendering in a different thread,possibly using GL,or does not use the animation framework or view hierarchy at all and you want to ensure that it is appropriately synchronized with the display,then use
    {@link Choreographer#postFrameCallback}.
  • … and that’s about it.
  • Each {@link Looper} thread has its own choreographer. Other threads can post callbacks to run on the choreographer but they will run on the {@link Looper}to which the choreographer belongs.

    再看一下postFrameCallback注释

    Posts a frame callback to run on the next frame.The callback runs once then is automatically removed.

    React Native的使用主要在EventDispatcher的内部类private class ScheduleDispatchFrameCallback implements Choreographer.FrameCallbackReactChoreographer与它的内部类private class ReactChoreographerDispatcher implements Choreographer.FrameCallback,还有用于view或者动画的就不说了。

    现在举个例子,点击一下view,这个事件是怎么传递的,点击事件肯定发生在java端。在ReactRootViewdispatchJSTouchEvent方法

    1. ...
    2. EventDispatcher eventDispatcher = reactContext.getNativeModule(UIManagerModule.class)
    3. .getEventDispatcher();
    4. mJSTouchDispatcher.handleTouchEvent(event,eventDispatcher);
    5.  
    6. //JSTouchDispatcher.java
    7. public void handleTouchEvent(MotionEvent ev,EventDispatcher eventDispatcher) {
    8. //这里面分为down,up move 等事件类别
    9.  
    10. mTargetTag = TouchTargetHelper.findTargetTagAndCoordinatesForTouch(
    11. ev.getX(),ev.getY(),mRootViewGroup,mTargetCoordinates,null);
    12. eventDispatcher.dispatchEvent(
    13. TouchEvent.obtain(
    14. mTargetTag,TouchEventType.START,ev,mGestureStartTime,mTargetCoordinates[0],mTargetCoordinates[1],mTouchEventCoalescingKeyHelper));
    15.  
    16. }

    最终包装成一个TouchEvent调用eventDispatcher.dispatchEvent,这里面主要是

    1. mEventStaging.add(event);//ArrayList<Event>

    把事件添加到一个待发送的列表里面。那什么是去处发送?是在ScheduleDispatchFrameCallback.doFrame

    1. @Override
    2. public void doFrame(long frameTimeNanos) {
    3. ....
    4. moveStagedEventsToDispatchQueue();
    5. ...
    6. mReactContext.runOnJSQueueThread(mDispatchEventsRunnable);
    7.  
    8. }

    调用moveStagedEventsToDispatchQueue在这个方法里面会对event再做一些处理,例如压缩,合并事件等,然后又把处理完的事件放到Event[] mEventsToDispatch = new Event[16];中。而在DispatchEventsRunnablerun方法

    1. @Override
    2. public void run() {
    3. for (int eventIdx = 0; eventIdx < mEventsToDispatchSize; eventIdx++) {
    4. Event event = mEventsToDispatch[eventIdx];
    5. ....
    6. event.dispatch(mRCTEventEmitter);
    7. event.dispose();
    8. ...
    9. }
    10. }
    11.  
    12. ->TouchEvent.dispatch->TouchesHelper.sendTouchEvent->rctEventEmitter.receiveTouches(
    13. type.getJSEventName(),pointers,changedIndices);

    RCTEventEmitter extends JavaScriptModule这个就是走上面的java->js的路子,动态代理->cpp->flush()->….

    简单点就是getJSModule后对js的方法调用都会触发上面MessageQueue.js的出队

    脚本执行

    这里简单说说React Nativejs引擎选择,都是webkitJSC,在iOS上是内置的,在Android上则是引入了一个完整的JSC,这也是为什么AndroidRN会大这么多的很重要的原因,至于为什么要引入一个完整的JSC而不是使用内置的js引擎,Android 4.4之前的android系统浏览器内核是WebKitAndroid4.4系统浏览器切换到了Chromium(内核是Webkit的分支Blink)。在Android平台已经启用V8作为JS引擎,Android 4.0以后只用到了JavaScriptCore中的WTF(Web Template Library)部分代码

    至于为啥不都使用V8,这个都是iOS的锅,看看chromeiOS上就是个WebView套个壳。。。

    还有其他的跨平台框架,例如weex,在Android上使用的是V8。现在网上也有对RNAndroid上移植的V8版本。
    onesubone/react-native-android-v8
    React Native Android V8接入
    这个是基于0.46的版本,还是可以跑起来的,但是RN的速度瓶颈貌似并不在js引擎。。

    最后再贴一下简单画的思维导图吧

    思维导图

    参考:

    facebook/react-native
    React Native Android 源码框架浅析(主流程及 Java 与 JS 双边通信)
    ReactNative源码篇
    吟游雪人

    ps:

    因为本人能力实在有限,上面很多都是连蒙带猜,算是个笔记性质的流水账,有用就看看,没用就算了,欢迎指出错误

    pps

    这篇本该在两星期之前完成的工作,一直拖到了现在。(一是因为懒),二是因为不知道该怎么更好的表述出来,因为一直贴代码体验实在是不好。(虽然现在还是这样的,但是源码分析的不贴代码怎么写)。但是感觉再不写点出来,过段时间又忘了,索性写出来算了,也不管效果了。。。凑合看吧。

    猜你在找的React相关文章