(源码版本:0.34,新版本(0.48)基本流程是不变的,建议跟着源码看看,哪个版本的倒影响不大)
这篇简单刨析一下React Native
是怎么在Android
上跑起来的,会从下面几个方面说说。
- 启动流程
- 通信机制
- 事件驱动
- 渲染原理
- 脚本执行
启动流程
React Native
在Android
上启动是从ReactRootView.startReactApplication
触发的,而ReactRootView
是继承FrameLayout
的,所以React Native
在Android
的操作都是在这个View
中进行的。
startReactApplication(ReactInstanceManager reactInstanceManager,String moduleName,@Nullable Bundle launchOptions)
这个方法参数第一个ReactInstanceManager
,实现是XReactInstanceManagerImpl
,可以理解在应用层对RN
的配置都是对这个类操作实现的。moduleName
是要启动的RN
的Component
的name
,是在js
的AppRegistry.registerComponent('xxx',() => App);
定义的。最后的launchOptions
是传过去的参数,可以在js
的Component
的props
中获取。
下一步到了mReactInstanceManager.createReactContextInBackground();
是在后台线程中创建RN
的ReactContext
上下文对象,然后到
//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.cpp
的initializeBridge
方法
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.cpp
的initializeBridge
方法
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.cpp
的JavaNativeModule
类和NewJavaNativeModule
类,对应Java
的JavaModuleWrapper.java
,就是jni
调用。
说到这里,现在只完成了bridge
环境的初步搭建,把jsbundle
扔到jsc
里面,还没真正拉起React Native
应用。还是回到上面那个AsyncTask
的onPostExecute
方法。看看执行完这么一大堆准备代码之后,是怎么拉起来整个应用的。
@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
的逻辑渲染,最终映射到Native
的View
上。后面会再详细说渲染的原理。同时会发现在 JSCExecutor
中每次 Java
调用 JS
之后会进行 Java
端的一个回调(从 JS
层的 MessageQueue.js
中获得累积的 JS Call
)。
通信机制
上面关于java
->js
已经体现的差不多了,实质就是 Java
与 JS
端都准备好一个 Module
映射表,然后当 Java
端调用 JS
代码时 Java
端通过查表动态代理创建一个与 JS 对应的 Module
对象,当调用这个 Module
的方法时 Java 端通过动态代理的 invoke
方法触发 C++
层,层层调用后通过 JSCExecutor
执行 JS
端队列中的映射查表找到 JS
端方法进行调用;js
->java
的调用会在渲染原理里面提到。
简单画了个图
渲染原理
现在以一个Image
如何渲染到Native
为例,说一下简单的流程。
当执行js
的脚本时候,是不知道nativeModule
的注册表的,因为nativeModule
的注册表只保存在java
和cpp
端,并没有直接传递到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
中的方法,在这个方法中,分promise
,sync
,其他
调用类型,最终都是调用了
__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_IDS
,METHOD_IDS
,PARAMS
放到queue
中,等待java
的调用,至于什么时候会触发java
的调用和为什么要这么设计,会在下面的事件驱动解释。调用JSCExecutor::flush()
。还有就是直接调用cpp
的nativeFlushQueueImmediate
,最终这两种方式都是调用了callNativeModules
,这个上面也说了,不再赘述啦。
下面再说一下Native
的view
创建过程,这个过程中View
的tag
起标记View
的作用,从java
拉起React Native
的attachMeasuredRootViewToInstance
方法中可以看到
appParams.putDouble("rootTag",initialProps);
把rootTag
通过bridge
带到了js
端,js
执行React
逻辑后,要创建一个Native
的View
,同时也把这个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
。
再通过这个rootTag
在js
的传递简单说一下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.js
的mountComponent
,根据上面的提示是可以跟到这里的。只挑简单的看,看这个方法里面的
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
,分别的updateView
,manageChildren
,UIManager
通过bridge
可以映射到java
的UIManagerModule.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.java
的ArrayDeque<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.FrameCallback
和ReactChoreographer
与它的内部类private class ReactChoreographerDispatcher implements Choreographer.FrameCallback
,还有用于view
或者动画的就不说了。
现在举个例子,点击一下view
,这个事件是怎么传递的,点击事件肯定发生在java
端。在ReactRootView
的dispatchJSTouchEvent
方法
...
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];
中。而在DispatchEventsRunnable
的run
方法中
@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 Native
的js引擎
选择,都是webkit
的JSC
,在iOS
上是内置的,在Android
上则是引入了一个完整的JSC
,这也是为什么Android
的RN
会大这么多的很重要的原因,至于为什么要引入一个完整的JSC
而不是使用内置的js
引擎,Android 4.4
之前的android
系统浏览器内核是WebKit
,Android4.4
系统浏览器切换到了Chromium
(内核是Webkit
的分支Blink
)。在Android
平台已经启用V8作为JS引擎,Android 4.0
以后只用到了JavaScriptCore
中的WTF(Web Template Library)部分代码。
至于为啥不都使用V8
,这个都是iOS
的锅,看看chrome
在iOS
上就是个WebView
套个壳。。。
还有其他的跨平台框架,例如weex
,在Android
上使用的是V8
。现在网上也有对RN
在Android
上移植的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
这篇本该在两星期之前完成的工作,一直拖到了现在。(一是因为懒),二是因为不知道该怎么更好的表述出来,因为一直贴代码体验实在是不好。(虽然现在还是这样的,但是源码分析的不贴代码怎么写)。但是感觉再不写点出来,过段时间又忘了,索性写出来算了,也不管效果了。。。凑合看吧。