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

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

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

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

    启动流程

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

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

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

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

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

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

    @Override
        protected Result<ReactApplicationContext> doInBackground(ReactContextInitParams... params) {
          ....
           return Result.of(createReactContext(jsExecutor,params[0].getJsBundleLoader()));
          ....
        }
    
      private ReactApplicationContext createReactContext(
          JavaScriptExecutor jsExecutor,JSBundleLoader jsBundleLoader) {
        ...
         NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder();//NativeModule的注册
        JavaScriptModuleRegistry.Builder jsModulesBuilder = new JavaScriptModuleRegistry.Builder();//jsModules的注册
        ...打包定义的各种modules到上面的注册表...
    
            //创建关键的CatalystInstanceImpl
            CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
            ...
            catalystInstance = catalystInstanceBuilder.build();
        ....
        //扔到js线程中加载js脚本
        catalystInstance.getReactQueueConfiguration().getJSQueueThread().callOnQueue(
            new Callable<Void>() {
              @Override
              public Void call() throws Exception {
                //让reactContext持有catalystInstance
                reactContext.initializeWithInstance(catalystInstance);
                ...
                catalystInstance.runJSBundle();
                return null;
              }
            }).get();
        }

    CatalystInstanceImpl的构造函数中有

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

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

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

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

    void Instance::initializeBridge(
        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) {
      callback_ = std::move(callback);
    
      //在js线程中包装nativeQueue和创建nativeToJsBridge_,后者在双向bridge起作用,不要仅仅看名字,内部还有一个JsToNativeBridge
      jsQueue->runOnQueueSync(
        [this,&jsef,moduleRegistry,jsQueue,nativeQueue=folly::makeMoveWrapper(std::move(nativeQueue))] () mutable {
          nativeToJsBridge_ = folly::make_unique<NativeToJsBridge>(
              jsef.get(),nativeQueue.move(),callback_);
        });
      CHECK(nativeToJsBridge_);
    }

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

    void Instance::loadScriptFromFile(const std::string& filename,const std::string& sourceURL) {
      ...检测文件合法性等...
      loadScriptFromString(std::move(buf),sourceURL);
    }
    
    void Instance::loadScriptFromString(std::unique_ptr<const JSBigString> string,std::string sourceURL) {
      callback_->incrementPendingJSCalls();//这个callback就是java层的CatalystInstanceImpl的BridgeCallback这个内部类。
      ...
      nativeToJsBridge_->loadApplicationScript(std::move(string),std::move(sourceURL));
    }
    
    void NativeToJsBridge::loadApplicationScript(std::unique_ptr<const JSBigString> script,std::string sourceURL) {
      m_mainExecutor->loadApplicationScript(std::move(script),std::move(sourceURL));
    }
    
    void JSCExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> script,std::string sourceURL) throw(JSException) {
        ...
         //使用webkit JSC去真正解释执行Javascript了!
         evaluateScript(m_context,jsScript,jsSourceURL);
         //绑定桥,核心是通过getGlobalObject将JS与C++通过webkit JSC bind
         bindBridge(); 
         flush();
        }
    
    void JSCExecutor::bindBridge() throw(JSException) {
      ...下面都是通过jsc 获取js的一下属性方法...
      auto global = Object::getGlobalObject(m_context);
      auto batchedBridgeValue = global.getProperty("__fbBatchedBridge");
    ...
      auto batchedBridge = batchedBridgeValue.asObject();
      m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty("callFunctionReturnFlushedQueue").asObject();
      m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty("invokeCallbackAndReturnFlushedQueue").asObject();
      //这个比较重要 获取MessageQueue.js的flushedQueue 下面就用到
      m_flushedQueueJS = batchedBridge.getProperty("flushedQueue").asObject();
    }
    
    //这个下面js->native的时候还会提到
    void JSCExecutor::flush() {
      ...真的烦,绕来绕去  m_flushedQueueJS看上面
      callNativeModules(m_flushedQueueJS->callAsFunction({}));
    }
    
    void JSCExecutor::callNativeModules(Value&& value) {
        ...
      try {
        auto calls = value.toJSONString();
        //class JsToNativeBridge : public react::ExecutorDelegate
        m_delegate->callNativeModules(*this,std::move(calls),true);
      } catch (...) {
       ...
      }
    }
    
      void callNativeModules(
          JSExecutor& executor,std::string callJSON,bool isEndOfBatch) override {
        ExecutorToken token = m_nativeToJs->getTokenForExecutor(executor);
        m_nativeQueue->runOnQueue([this,token,callJSON=std::move(callJSON),isEndOfBatch] {
          for (auto& call : react::parseMethodCalls(callJSON)) {
            //快完了  这个是ModuleRegistry.cpp 是在initializeBridge间接创建包装nativemodule的
            m_registry->callNativeMethod(
              token,call.moduleId,call.methodId,std::move(call.arguments),call.callId);
          }
          if (isEndOfBatch) {
            //又见到了这个callback
            m_callback->onBatchComplete();
            m_callback->decrementPendingJSCalls();
          }
        });
      }
    
    void ModuleRegistry::callNativeMethod(ExecutorToken token,unsigned int moduleId,unsigned int methodId,folly::dynamic&& params,int callId) {
     ...
    
      modules_[moduleId]->invoke(token,methodId,std::move(params));
    
    }

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

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

    @Override
        protected void onPostExecute(Result<ReactApplicationContext> result) {
          ....
           setupReactContext(result.get());
        }
    
        private void setupReactContext(ReactApplicationContext reactContext) {
        ...各种listener回调,通知birdge就绪,reactContext创建完成
        for (ReactRootView rootView : mAttachedRootViews) {
          attachMeasuredRootViewToInstance(rootView,catalystInstance);
        }
        ...各种listener回调,通知birdge就绪,reactContext创建完成
      }
    
    
    private void attachMeasuredRootViewToInstance(ReactRootView rootView,CatalystInstance catalystInstance) {
       ....
        UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
        int rootTag = uiManagerModule.addMeasuredRootView(rootView);
        rootView.setRootViewTag(rootTag);
        @Nullable Bundle launchOptions = rootView.getLaunchOptions();
        WritableMap initialProps = Arguments.makeNativeMap(launchOptions);
        String jsAppModuleName = rootView.getJSModuleName();
    
        WritableNativeMap appParams = new WritableNativeMap();
        appParams.putDouble("rootTag",rootTag);
        appParams.putMap("initialProps",initialProps);
        //真正拉起react native 的地方
        catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName,appParams);
      }

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

    @Override
      public <T extends JavaScriptModule> T getJSModule(ExecutorToken executorToken,Class<T> jsInterface) {
        //进入JSModuleRegistry中
        return Assertions.assertNotNull(mJSModuleRegistry)
            .getJavaScriptModule(this,executorToken,jsInterface);
      }
    
      //JavaScriptModuleRegistry.java
       public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
        CatalystInstance instance,ExecutorToken executorToken,Class<T> moduleInterface) {
        HashMap<Class<? extends JavaScriptModule>,JavaScriptModule> instancesForContext =
            mModuleInstances.get(executorToken);
        if (instancesForContext == null) {
          instancesForContext = new HashMap<>();
          //缓存一下 方便后面再使用
          mModuleInstances.put(executorToken,instancesForContext);
        }
        JavaScriptModule module = instancesForContext.get(moduleInterface);
        if (module != null) {
          //命中缓存 直接返回
          return (T) module;
        }
        JavaScriptModuleRegistration registration =
          ...
          //很明显 动态代理 重点关注JavaScriptModuleInvocationHandler的invoke方法
        JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
            moduleInterface.getClassLoader(),new Class[]{moduleInterface},new JavaScriptModuleInvocationHandler(executorToken,instance,registration));
        instancesForContext.put(moduleInterface,interfaceProxy);
        return (T) interfaceProxy;
      }
    
      @Override
        public @Nullable Object invoke(Object proxy,Method method,@Nullable Object[] args) throws Throwable {
          ....
          //又跑到了CatalystInstanceImpl.java中。。。然后又桥接到了CatalystInstanceImpl.cpp中,同样会调用instance的对应方法,直接看吧
          mCatalystInstance.callFunction(
            executorToken,mModuleRegistration.getName(),method.getName(),jsArgs
          );
          return null;
        }
    
    void Instance::callJSFunction(ExecutorToken token,std::string&& module,std::string&& method,folly::dynamic&& params) {
      callback_->incrementPendingJSCalls();//这个回调不多说
      //....接着跟吧
      nativeToJsBridge_->callFunction(token,std::move(module),std::move(method),std::move(params));
    }  
    
    //又会进入executor->callFunction(module,method,arguments);
    void JSCExecutor::callFunction(const std::string& moduleId,const std::string& methodId,const folly::dynamic& arguments) {
        ....
      auto result = [&] {
        try {
          //被桥接到MessageQueue.js的callFunctionReturnFlushedQueue方法
          return m_callFunctionReturnFlushedQueueJS->callAsFunction({
            Value(m_context,String::createExpectingAscii(moduleId)),Value(m_context,String::createExpectingAscii(methodId)),Value::fromDynamic(m_context,std::move(arguments))
          });
        } catch (...) {
          std::throw_with_nested(
            std::runtime_error("Error calling function: " + moduleId + ":" + methodId));
        }
      }();
      //顺便还会调用一下native的 这个会在后面再说一下
      callNativeModules(std::move(result));
    }
    
     callFunctionReturnFlushedQueue(module,args) {
            guard(() => {
                //执行js的function
                this.__callFunction(module,args);
                this.__callImmediates();
            });
            //取出积攒在queue中的action返回给上面的,最终在java中执行
            return this.flushedQueue();
        }
    
    __callFunction(module: string,method: string,args: any) {
           ...
           //根据module名,方法名和参数执行js方法
            const result = moduleMethods[method].apply(moduleMethods,args);
            return result;
        }
        //那什么时候把js的module注册到moduleMethods中呢
    //AppRegistry.js
    BatchedBridge.registerCallableModule(
      'AppRegistry',AppRegistry
    );
    //BatchedBridge是啥?
    const BatchedBridge = new MessageQueue(
      () => global.__fbBatchedBridgeConfig,serializeNativeParams
    );
    registerCallableModule(name,methods) {
            this._callableModules[name] = methods;
        }

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

    runApplication: function(appKey: string,appParameters: any): void {
       ...
        runnables[appKey].run(appParameters);
      },//而runnables是在什么时候被添加的??下面
    
      registerComponent: function(appKey: string,getComponentFunc: ComponentProvider): string {
        runnables[appKey] = {
          run: (appParameters) =>
            renderApplication(getComponentFunc(),appParameters.initialProps,appParameters.rootTag)
        };
        return appKey;
      },//而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端。所有当执行到

    import {
        Image,} from 'react-native';

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

    const ReactNative = {
        ...
        get Image() { return require('Image'); },...
    }
    ...
    module.exports = ReactNative;
    
    //Image.android.js
    
    var NativeModules = require('NativeModules');
    
    //NativeModules.js
    
    const NativeModules = {};
    Object.keys(RemoteModules).forEach((moduleName) => {
      Object.defineProperty(NativeModules,moduleName,{
        configurable: true,enumerable: true,get: () => {
          let module = RemoteModules[moduleName];
          if (module && typeof module.moduleID === 'number' && global.nativeRequireModuleConfig) {
          //nativeRequireModuleConfig映射到JSCExecutor.cpp
            const config = global.nativeRequireModuleConfig(moduleName);
            module = config && BatchedBridge.processModuleConfig(config,module.moduleID);
            RemoteModules[moduleName] = module;
          }
          Object.defineProperty(NativeModules,{
            configurable: true,value: module,});
          return module;
        },});
    });
    
    module.exports = NativeModules;
    
    //cpp
    JSCExecutor::nativeRequireModuleConfig->JsToNativeBridge::getModuleConfig->ModuleRegistry::getConfig
    
    folly::dynamic ModuleRegistry::getConfig(const std::string& name) {
    
    ...
      NativeModule* module = modules_[it->second].get();
    ...
      //最终反射调用JavaModuleWrapper.java的getConstants
      folly::dynamic constants = module->getConstants();
    ...
      //最终反射调用JavaModuleWrapper.java的getMethods
      //返回对应module中所有@ReactMethod注解的方法
      std::vector<MethodDescriptor> methods = module->getMethods();
    
    //modules_在哪赋值?
    //ModuleRegistryHolder.cpp构造函数,这个类上面有提到,回去看看
    //registry_ = std::make_shared<ModuleRegistry>(std::move(modules));
    }

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

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

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

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

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

    appParams.putDouble("rootTag",initialProps);

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

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

    final int tag = mNextRootViewTag;//默认是1
        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

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

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

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

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

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

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

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

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

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

    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方法

    ...
      EventDispatcher eventDispatcher = reactContext.getNativeModule(UIManagerModule.class)
          .getEventDispatcher();
        mJSTouchDispatcher.handleTouchEvent(event,eventDispatcher);
    
    //JSTouchDispatcher.java
      public void handleTouchEvent(MotionEvent ev,EventDispatcher eventDispatcher) {
        //这里面分为down,up move 等事件类别
    
         mTargetTag = TouchTargetHelper.findTargetTagAndCoordinatesForTouch(
            ev.getX(),ev.getY(),mRootViewGroup,mTargetCoordinates,null);
          eventDispatcher.dispatchEvent(
            TouchEvent.obtain(
              mTargetTag,TouchEventType.START,ev,mGestureStartTime,mTargetCoordinates[0],mTargetCoordinates[1],mTouchEventCoalescingKeyHelper));
    
    }

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

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

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

    @Override
        public void doFrame(long frameTimeNanos) {
        ....
          moveStagedEventsToDispatchQueue();
        ...
           mReactContext.runOnJSQueueThread(mDispatchEventsRunnable);
    
        }

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

    @Override
        public void run() {
         for (int eventIdx = 0; eventIdx < mEventsToDispatchSize; eventIdx++) {
                Event event = mEventsToDispatch[eventIdx];
                ....
                event.dispatch(mRCTEventEmitter);
                event.dispose();
                ...
                }
        }
    
    ->TouchEvent.dispatch->TouchesHelper.sendTouchEvent->rctEventEmitter.receiveTouches(
            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相关文章