原文:http://www.javashuo.com/article/p-respfedz-eh.htmlhtml
咱们所说的[通讯],指的是RN中Java和js的通讯,也就是js部分中的那些jsx代码是如何转化成一个java层真实的view和事件的,java层又是如何调用js来找出它所须要的那些view和事件的。java
简单的说,RN的两端通讯靠的是一张配置表,java端和js端持有同一张表,通讯的时候就是靠这张表的各个条目的对应来进行的。react
大体的就是和上面这张图同样,两端各持有一份相同的config,config中有一些已经注册的模块,两端的通讯就是经过传输这样的“A”,“B”或者”C”来实现的。这个config对应到RN的代码是NativeModuleRegistry和JavaScriptModuleRegistry。若是你们想象不出来的话我能够给你们打个比喻,java端和js端的通讯就比如一个中国人和一个美国人在对话,而这个config,也就是注册表就至关于两个翻译,有了翻译两个语言不通的人才能正常交流。那这两张表是如何生成的呢?仍是让咱们从代码中寻找答案吧。android
首先咱们知道在使用RN的时候,咱们对应的activity要继承自ReactActivity而且重写一个叫作getPackages的方法。git
@Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage() ); }
这个MainReactPackage是RN帮咱们生成好的,其中定义了一些基础的组件和事件,具体就不说了,你们能够本身去看一下源码。若是你想要自定义一些组件或者事件的话必需要本身去写一个package,至于怎么写你们看我前面提到的那一系列文章就知道了。而咱们前面提到的那两个注册表——NativeModuleRegistry和JavaScriptModuleRegistry就是经过这样的package去生成的,具体方法咱们看下去就知道了。json
既然咱们的activity继承自了ReactActivity,那咱们就去看看ReactActivity里面作了什么。第一个要看的固然是onCreate函数。react-native
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) { // Get permission to show redbox in dev builds. if (!Settings.canDrawOverlays(this)) { Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); startActivity(serviceIntent); FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE); Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show(); } } mReactInstanceManager = createReactInstanceManager(); ReactRootView mReactRootView = createRootView(); mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName(), getLaunchOptions()); setContentView(mReactRootView); }
能够看到咱们建立了一个ReactInstanceManager,看看是怎么建立的。缓存
protected ReactInstanceManager createReactInstanceManager() { ReactInstanceManager.Builder builder = ReactInstanceManager.builder() .setApplication(getApplication()) .setJSMainModuleName(getJSMainModuleName()) .setUseDeveloperSupport(getUseDeveloperSupport()) .setInitialLifecycleState(mLifecycleState); for (ReactPackage reactPackage : getPackages()) { builder.addPackage(reactPackage); } String jsBundleFile = getJSBundleFile(); if (jsBundleFile != null) { builder.setJSBundleFile(jsBundleFile); } else { builder.setBundleAssetName(getBundleAssetName()); } return builder.build(); }
中间有一段这样的代码app
for (ReactPackage reactPackage : getPackages()) { builder.addPackage(reactPackage); }
经过builder模式把咱们的package注入到了builder中而且最后调用build方法建立出一个ReactInstanceManagerImpl实例。框架
咱们回过头来看onCreate函数,在这以后咱们建立一个ReactRootView做为咱们的根视图,而且调用它的startReactApplication函数,从函数名字就能够看出来,这个函数的做用很是重要,从这儿开始,算是启动了咱们的RN程序。
在startReactApplication函数中咱们调用了ReactInstanceManager的createReactContextInBackground()方法去构造属于RN程序的上下文。在这个方法中会去判断是不是开发模式,你们能够在本身的activity中重写getUseDeveloperSupport()去更改模式。模式不一样的主要区别在于获取JSBundle的方式不一样。若是你是开发模式的,就会从server端获取,若是不是,则是从文件中获取。这里咱们只关注前者。最终会走到onJSBundleLoadedFromServer方法。
private void onJSBundleLoadedFromServer() { recreateReactContextInBackground( new JSCJavaScriptExecutor.Factory(), JSBundleLoader.createCachedBundleFromNetworkLoader( mDevSupportManager.getSourceUrl(), mDevSupportManager.getDownloadedJSBundleFile())); } private void recreateReactContextInBackground( JavaScriptExecutor.Factory jsExecutorFactory, JSBundleLoader jsBundleLoader) { .......... mReactContextInitAsyncTask = new ReactContextInitAsyncTask(); mReactContextInitAsyncTask.execute(initParams); }
在该方法中咱们调用JSBundleLoader的createCachedBundleFromNetworkLoader方法去建立了一个JSBundleLoader。它的主要做用是去加载JSBundle。你们能够去看看JSBundleLoader这个类,其中还有两种建立loader的方式,若是咱们不是开发模式,调用的是createFileLoader,也就是说release的状况下咱们须要用gradle生成了JSBundle以后将其放在assets目录上或者文件中。
下面让咱们看看以后的recreateReactContextInBackground方法。
它会调用了一个叫作mReactContextInitAsyncTask的AsyncTask去执行异步任务。
@Override protected Result<ReactApplicationContext> doInBackground(ReactContextInitParams... params) { Assertions.assertCondition(params != null && params.length > 0 && params[0] != null); try { JavaScriptExecutor jsExecutor = params[0].getJsExecutorFactory().create( mJSCConfig == null ? new WritableNativeMap() : mJSCConfig.getConfigMap()); return Result.of(createReactContext(jsExecutor, params[0].getJsBundleLoader())); } catch (Exception e) { // Pass exception to onPostExecute() so it can be handled on the main thread return Result.of(e); } }
咱们能够看到它的doInBackground方法调用了createReactContext()方法去建立上下文。
private ReactApplicationContext createReactContext( JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) { FLog.i(ReactConstants.TAG, "Creating react context."); ReactMarker.logMarker(CREATE_REACT_CONTEXT_START); mSourceUrl = jsBundleLoader.getSourceUrl(); NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder(); JavaScriptModulesConfig.Builder jsModulesBuilder = new JavaScriptModulesConfig.Builder(); ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext); if (mUseDeveloperSupport) { reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager); } ReactMarker.logMarker(PROCESS_PACKAGES_START); Systrace.beginSection( Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createAndProcessCoreModulesPackage"); try { CoreModulesPackage coreModulesPackage = new CoreModulesPackage(this, mBackBtnHandler, mUIImplementationProvider); processPackage(coreModulesPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); } // TODO(6818138): Solve use-case of native/js modules overriding for (ReactPackage reactPackage : mPackages) { Systrace.beginSection( Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createAndProcessCustomReactPackage"); try { processPackage(reactPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); } } ReactMarker.logMarker(PROCESS_PACKAGES_END); ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_START); Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry"); NativeModuleRegistry nativeModuleRegistry; try { nativeModuleRegistry = nativeRegistryBuilder.build(); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END); } ReactMarker.logMarker(BUILD_JS_MODULE_CONFIG_START); Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "buildJSModuleConfig"); JavaScriptModulesConfig javaScriptModulesConfig; try { javaScriptModulesConfig = jsModulesBuilder.build(); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); ReactMarker.logMarker(BUILD_JS_MODULE_CONFIG_END); } NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null ? mNativeModuleCallExceptionHandler : mDevSupportManager; CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder() .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()) .setJSExecutor(jsExecutor) .setRegistry(nativeModuleRegistry) .setJSModulesConfig(javaScriptModulesConfig) .setJSBundleLoader(jsBundleLoader) .setNativeModuleCallExceptionHandler(exceptionHandler); ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START); // CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance"); CatalystInstance catalystInstance; try { catalystInstance = catalystInstanceBuilder.build(); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END); } if (mBridgeIdleDebugListener != null) { catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener); } reactContext.initializeWithInstance(catalystInstance); ReactMarker.logMarker(RUN_JS_BUNDLE_START); Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "runJSBundle"); try { catalystInstance.runJSBundle(); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); ReactMarker.logMarker(RUN_JS_BUNDLE_END); } return reactContext; }
这个方法的代码就比较多了,可是咱们如今只看咱们所关注的。你们应该还记得咱们的关注点吧?[两个注册表NativeModuleRegistry和JavaScriptModuleRegistry是如何生成的]。这里给出了答案。
NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder(); JavaScriptModulesConfig.Builder jsModulesBuilder = new JavaScriptModulesConfig.Builder();
首先建立出两个builder。
try { CoreModulesPackage coreModulesPackage = new CoreModulesPackage(this, mBackBtnHandler, mUIImplementationProvider); processPackage(coreModulesPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); }
而后会去new一个CoreModulesPackage而且使用了processPackage方法去处理它,这个CoreModulesPackage里面定义了RN框架核心的一些Java和JS的module。
下面让咱们看看processPackage方法。
private void processPackage( ReactPackage reactPackage, ReactApplicationContext reactContext, NativeModuleRegistry.Builder nativeRegistryBuilder, JavaScriptModulesConfig.Builder jsModulesBuilder) { for (NativeModule nativeModule : reactPackage.createNativeModules(reactContext)) { nativeRegistryBuilder.add(nativeModule); } for (Class<? extends JavaScriptModule> jsModuleClass : reactPackage.createJSModules()) { jsModulesBuilder.add(jsModuleClass); } }
很简单,拿到具体的native和JS的module把它们添加到对应的builder中。
再处理完了CoreModulesPackage以后,程序又会去处理咱们在activity中注入的那些package。
for (ReactPackage reactPackage : mPackages) { Systrace.beginSection( Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createAndProcessCustomReactPackage"); try { processPackage(reactPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); } }
接下去就是生成注册表了。
try { nativeModuleRegistry = nativeRegistryBuilder.build(); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END); } try { javaScriptModulesConfig = jsModulesBuilder.build(); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); ReactMarker.logMarker(BUILD_JS_MODULE_CONFIG_END); }
至此,咱们就把全部的packages,包括RN核心的CoreModulesPackage和咱们activity本身注入的package里面的各个modules所有写到了对应Registry的builder中。
如今这两份注册表是存在于java端的,那要怎么传输到JS端呢?咱们继续看下去。
再建立完了对应的注册表以后,ReactInstanceManagerImpl会经过builder模式去建立一个CatalystInstance的实例CatalystInstanceImpl。在CatalystInstanceImpl的构造函数中会去建立一个ReactBridge。而且会调用initializeBridge(jsExecutor, jsModulesConfig)这个方法。在这个方法中会去经过ReactBridge向C层传递一些数据,其中有这么一段:
bridge.setGlobalVariable( "__fbBatchedBridgeConfig", buildModulesConfigJSONProperty(mJavaRegistry, jsModulesConfig));
调用了bridge的setGlobalVariable方法,这是一个native的方法。
public native void setGlobalVariable(String propertyName, String jsonEncodedArgument);
这个方法的做用就是先把JavaRegistry格式化成json,而且调用C层的代码传输到js端。因为本人C层学艺不精,能看懂个大概,怕会有细节讲错,就不带你们进行分析了。
到这里,真相就水落石出了,咱们来总结一下吧。
(1) 在程序启动的时候,也就是ReactActivity的onCreate函数中,咱们会去建立一个ReactInstanceManagerImpl对象
(2) 经过ReactRootView的startReactApplication方法开启整个RN世界的大门
(3) 在这个方法中,咱们会经过一个AsyncTask去建立ReactContext
(4) 在建立ReactContext过程当中,咱们把咱们本身注入(MainReactPackage)的和系统生成(CoreModulesPackage)的package经过processPackage方法将其中的各个modules注入到了对应的Registry中
(5) 最后经过CatalystInstanceImpl中的ReactBridge将java的注册表经过jni传输到了JS层。
这样,js层就获取到了java层的全部接口和方法,至关于一个美国人身边有了觉得中文翻译。而js层的注册表原本就是由java层生成的,因此就至关于一个中国人身边有了一个英文翻译,今后他们就能够愉快的交流了。
涉及到的重要的类:
ReactInstanceManagerImpl,ReactContext,CatalystInstanceImpl,ReactBridge。
前面咱们讲了两端通讯的方式和注册表是如何从Java端发送到js端的,下面让咱们讲讲这样的准备工做完成之后,java是如何调用js的方法的。
首先,通过上面的学习,其实这个问题已经有了一个初步的答案了,由于[将JavaRegistry从java端传输到js端]这个过程就是一个java向js通讯的过程,具体的过程在上一节的总结中已经说了,让咱们回想一下,以前全部的事情都是在ReactInstanceManagerImpl中ReactContextInitAsyncTask的doInBackground方法中完成的,那这个方法完成以后又作了什么呢?
@Override protected void onPostExecute(Result<ReactApplicationContext> result) { try { setupReactContext(result.get()); } catch (Exception e) { mDevSupportManager.handleException(e); } finally { mReactContextInitAsyncTask = null; } // Handle enqueued request to re-initialize react context. if (mPendingReactContextInitParams != null) { recreateReactContextInBackground( mPendingReactContextInitParams.getJsExecutorFactory(), mPendingReactContextInitParams.getJsBundleLoader()); mPendingReactContextInitParams = null; } }
能够看到,在onPostExecute方法中调用了setupReactContext方法,在这个方法中会去调用attachMeasuredRootViewToInstance方法。
private void attachMeasuredRootViewToInstance( ReactRootView rootView, CatalystInstance catalystInstance) { ....... ....... catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams); }
这个方法的最后用了咱们的CatalystInstanceImpl的getJSModule方法,它会去调用JavaScriptModuleRegistry的getJSModule方法,获取对应的JavaScriptModule,也就是从注册表中获取对应的模块。
public synchronized <T extends JavaScriptModule> T getJavaScriptModule(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 = Assertions.assertNotNull( mModuleRegistrations.get(moduleInterface), "JS module " + moduleInterface.getSimpleName() + " hasn't been registered!"); JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance( moduleInterface.getClassLoader(), new Class[]{moduleInterface}, new JavaScriptModuleInvocationHandler(executorToken, mCatalystInstance, registration)); instancesForContext.put(moduleInterface, interfaceProxy); return (T) interfaceProxy; }
这个方法就比较神奇了,首先去缓存中找,若是找到就返回,没找到就去建立,怎么建立的呢,用的是动态代理!
JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance( moduleInterface.getClassLoader(), new Class[]{moduleInterface}, new JavaScriptModuleInvocationHandler(executorToken, mCatalystInstance, registration));
这里你们必需要对动态代理有所了解,能够本身去找相关的知识。让咱们看看JavaScriptModuleInvocationHandler。
@Override public @Nullable Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ExecutorToken executorToken = mExecutorToken.get(); if (executorToken == null) { FLog.w(ReactConstants.TAG, "Dropping JS call, ExecutorToken went away..."); return null; } String tracingName = mModuleRegistration.getTracingName(method); mCatalystInstance.callFunction( executorToken, mModuleRegistration.getModuleId(), mModuleRegistration.getMethodId(method), Arguments.fromJavaArgs(args), tracingName); return null; }
咱们看它最核心的invoke方法。里面获取了调用方法的moduleId,methodId和参数,而后调用了CatalystInstanceImpl的callFunction去执行。
@Override public void callFunction( ExecutorToken executorToken, int moduleId, int methodId, NativeArray arguments, String tracingName) { synchronized (mJavaToJSCallsTeardownLock) { if (mDestroyed) { FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed."); return; } incrementPendingJSCalls(); Assertions.assertNotNull(mBridge).callFunction(executorToken, moduleId, methodId, arguments, tracingName); } }
直接调用了ReactBridge的同名函数。
public native void callFunction(ExecutorToken executorToken, int moduleId, int methodId, NativeArray arguments, String tracingName);
能够看到又是一个native函数,具体做用就是将想用调用的方法对应的moduleId,methodId和arguments经过jni传递到js端进行调用。而咱们这边调用的是AppRegistry的runApplication方法,这个方法在js端的做用就是开始运行整个js程序,从而将咱们的RN程序真正的跑起来。
首先,对于咱们java端要调用的js端的类和方法,咱们都必需要注册到js的注册表中,这个过程在上一部分的分析中已经带你们走过了。当真正要调用的时候,步骤是这样的:
(1) 调用CatalystInstanceImpl这个类的getJSModule方法去获得对应的JSModule
(2) CatalysInstanceImpl其实是调用JavaScriptModuleRegistry的getJSModule方法去获取注册在其中的module
(3) 而后经过动态代理拿到方法的各类参数,包括moduleId,methodId和params
(4) 经过ReactBridge调用jni传递到C层
(5) 经过C层再传递到js层。
涉及到的重要的类:
CatalystInstanceImpl,JavaScriptModuleRegistry,JavaScriptModuleInvocationHandler,ReactBridge。
经过这个图配合上代码应该能比较好的理解了。
RN的js调java的流程能够说是让我以为最新颖的地方,具体就是js不是直接经过注册接口去调用java方法的,而是将对应的的参数(moduleId和methodId)push到一个messageQueue中,等待java层的事件来驱动它,当java层的事件传递过来之后,js层把messageQueue中全部的数据返回给java层,再经过注册表JavaRegistry去调用方法。
首先,咱们说了js层是把对应的参数push到messageQueue中,具体的方法是MessageQueue.js的__nativeCall方法。
__nativeCall(module, method, params, onFail, onSucc) { ......... this._queue[MODULE_IDS].push(module); this._queue[METHOD_IDS].push(method); this._queue[PARAMS].push(params); ........... }
能够看到它把对应的module,method和params push到了队列里面,而后就是等待java层的事件驱动。
java层的事件驱动其实也能够当作java层向js层的通讯,最终会走到MessageQueue.js的callFunctionReturnFlushedQueue方法和invokeCallbackAndReturnFlushedQueue方法。
callFunctionReturnFlushedQueue(module, method, args) { guard(() => { this.__callFunction(module, method, args); this.__callImmediates(); }); return this.flushedQueue(); }
调用了flushedQueue将MessageQueue中的全部数据经过C层发往java层。
到了java层之后,会回调到NativeModulesReactCallback类执行call方法。
private class NativeModulesReactCallback implements ReactCallback { @Override public void call(ExecutorToken executorToken, int moduleId, int methodId, ReadableNativeArray parameters) { mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread(); synchronized (mJSToJavaCallsTeardownLock) { // Suppress any callbacks if destroyed - will only lead to sadness. if (mDestroyed) { return; } mJavaRegistry.call(CatalystInstanceImpl.this, executorToken, moduleId, methodId, parameters); } } ..... }
能够看到里面经过JavaRegistry调用了它的call方法。
/* package */ void call( CatalystInstance catalystInstance, ExecutorToken executorToken, int moduleId, int methodId, ReadableNativeArray parameters) { ModuleDefinition definition = mModuleTable.get(moduleId); if (definition == null) { throw new RuntimeException("Call to unknown module: " + moduleId); } definition.call(catalystInstance, executorToken, methodId, parameters); }
拿到对应的module,调用call方法。
public void call( CatalystInstance catalystInstance, ExecutorToken executorToken, int methodId, ReadableNativeArray parameters) { MethodRegistration method = this.methods.get(methodId); Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, method.tracingName); try { this.methods.get(methodId).method.invoke(catalystInstance, executorToken, parameters); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); } } }
其中根据methodId拿到对应module的方法,执行invoke。
最终执行的是BaseJavaModule的invoke方法。
@Override public void invoke(CatalystInstance catalystInstance, ExecutorToken executorToken, ReadableNativeArray parameters) { ......... mMethod.invoke(BaseJavaModule.this, mArguments); ......... }
经过反射调用最终的方法。
这里咱们重点要了解的就是js向java的通讯靠的是事件驱动模式。
(1) JS将方法的对应参数push到MessageQueue中,等java端事件传递
(2) Java端事件触发之后,JS层将MessageQueue中的数据经过C层传递给java层
(3) C层调用一开始注册在其中的NativeModulesReactCallback
(4 而后经过JavaRegistry这个Java注册表拿到对应的module和method
(5) 经过反射执行方法。
涉及到的重要的类:
MessageQueue(JS层),NativeModulesReactCallback,JavaRegistry。
老规矩,经过图配合代码来理解流程。
最后咱们经过总结一下前面提到的几个重要的类的做用来加深印象。
ReactInstanceManager:它的做用是建立出ReactContext,CatalystInstance等类,解析package生成注册表,而且配合ReactRootView管理View的建立,生命周期等功能。
ReactContext:继承自ContextWrapper,是RN程序本身的上下文,咱们能够经过getContext()去得到,里面有CatalystInstance实例,能够去得到Java和JS的module。
ReactRootView:RN程序的根视图,startReactApplication方法开启RN世界的大门。
CatalystInstance:Java端通讯的管理类,提供通讯的环境,方法和回调方法,内部经过ReactBridge进行通讯。
ReactBridge:通讯的核心类,经过jni的方式进行通讯。
NativeModuleRegistry:Java接口的注册表。
JavascriptModuleRegistry:JS接口的注册表。
CoreModulePackage:RN核心框架的package,包括Java接口和js接口,前文提到的AppResgitry就是在这里面注册的。
MainReactPackage:RN帮咱们封装的一些通用的Java组件和事件。
JsBundleLoader:用于加载JSBundle的类,其中会根据应用的状况建立不一样的loader。
JSBundle:存有js核心逻辑,在release环境下要经过gradle任务去建立而且放在对应的目录下。
很差意思各位!!这里因为本人粗心的缘由,代码没看全,有一个地方出错了,这里写一个勘误,若是形成了你们的困扰我再次说一声很差意思!
前面我说过,JS调Java的机制是[JS把对应的moduleId,methodId和params push到queue中,等待native调用js,而后把MessageQueue中的数据发送到C层再经过jni转到java层]。可是今天公司里的大神在和咱们讨论RN的时候纠正了个人这个错误。
咱们一块儿看一下MessageQueue.js的__nativeCall方法
__nativeCall(module, method, params, onFail, onSucc) { .............. this._queue[MODULE_IDS].push(module); this._queue[METHOD_IDS].push(method); this._queue[PARAMS].push(params); var now = new Date().getTime(); if (global.nativeFlushQueueImmediate && now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS) { global.nativeFlushQueueImmediate(this._queue); this._queue = [[], [], [], this._callID]; this._lastFlush = now; } Systrace.counterEvent('pending_js_to_native_queue', this._queue[0].length); if (__DEV__ && SPY_MODE && isFinite(module)) { console.log('JS->N : ' + this._remoteModuleTable[module] + '.' + this._remoteMethodTable[module][method] + '(' + JSON.stringify(params) + ')'); } }
以前的文章只分析了前面的三个queue.push,可是你们能够看一下后面的一段:
var now = new Date().getTime(); if (global.nativeFlushQueueImmediate && now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS) { global.nativeFlushQueueImmediate(this._queue); this._queue = [[], [], [], this._callID]; this._lastFlush = now; }
它会去判断两次调用的时差,若是大于MIN_TIME_BETWEEN_FLUSHES_MS(5ms)的话,会调用global.nativeFlushQueueImmediate(this._queue);这个方法去主动把数据传递到C层的。也就是说,若是你两次的通讯时间很短,小于5ms了,那就和我以前讲的同样,可是若是大于5ms,RN在JS端会主动传递数据的,这里必定要注意了!!
—— 完 ——