編輯:關於Android編程
近段時間來Android上最火的框架非react native莫屬了,這裡我不去評價這個框架的好壞,畢竟只有用過的人才會有深刻的體會。但是我個人有一個習慣,在使用一個開源庫之前,一定要看過它的源碼,不說百分百搞懂吧,至少得弄清楚它的工作原理,所以在使用RN之前我就看了看它的源碼。不看不知道,一看嚇一跳,它其中最核心的那一部分——java和js的通信寫的確實是非常的精妙,把整個流程搞懂以後讓我受益無窮。
這裡插一句題外話,阿裡的weex也馬上就要開源了,我身邊的小伙伴也有已經拿到源碼投身於其中的,等到它開源的時候我也會去看看它的源碼,了解下它和RN的區別到底是什麼。
廢話也不說了,讓我們好好看看RN的通信機制吧。
在看這篇文章之前,你得確保你有一定的RN開發基礎,如果是零基礎的同學,建議大家先去看看這個系列的文章,裡面非常清楚的介紹了如何使用RN來進行開發。當然如果你不滿足僅僅是[了解]的話,也可以去網上查閱關於RN的一些資料,其實裡面一些東西是非常值得一看的,比如virtual DOM,diff機制等等。
我們所說的[通信],指的是RN中Java和js的通信,也就是js部分中的那些jsx代碼是如何轉化成一個java層真實的view和事件的,java層又是如何調用js來找出它所需要的那些view和事件的。
簡單的說,RN的兩端通信靠的是一張配置表,java端和js端持有同一張表,通信的時候就是靠這張表的各個條目的對應來進行的。

大致的就是和上面這張圖一樣,兩端各持有一份相同的config,config中有一些已經注冊的模塊,兩端的通信就是通過傳輸這樣的“A”,“B”或者”C”來實現的。這個config對應到RN的代碼是NativeModuleRegistry和JavaScriptModuleRegistry。如果大家想象不出來的話我可以給大家打個比喻,java端和js端的通信就好比一個中國人和一個美國人在對話,而這個config,也就是注冊表就相當於兩個翻譯,有了翻譯兩個語言不通的人才能正常交流。那這兩張表是如何生成的呢?還是讓我們從代碼中尋找答案吧。
首先我們知道在使用RN的時候,我們對應的activity要繼承自ReactActivity並且重寫一個叫做getPackages的方法。
@Override
protected List getPackages() {
return Arrays.asList(
new MainReactPackage()
);
}
這個MainReactPackage是RN幫我們生成好的,其中定義了一些基礎的組件和事件,具體就不說了,大家可以自己去看一下源碼。如果你想要自定義一些組件或者事件的話必須要自己去寫一個package,至於怎麼寫大家看我前面提到的那一系列文章就知道了。而我們前面提到的那兩個注冊表——NativeModuleRegistry和JavaScriptModuleRegistry就是通過這樣的package去生成的,具體方法我們看下去就知道了。
既然我們的activity繼承自了ReactActivity,那我們就去看看ReactActivity裡面做了什麼。第一個要看的當然是onCreate函數。
@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();
}
中間有一段這樣的代碼
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 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();
首先
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 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 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 getJavaScriptModule(ExecutorToken executorToken, Class moduleInterface) {
HashMap
這個方法就比較神奇了,首先去緩存中找,如果找到就返回,沒找到就去創建,怎麼創建的呢,用的是動態代理!
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任務去創建並且放在對應的目錄下。
Android Service生命周期及用法
Service概念及用途:Android中的服務,它與Activity不同,它是不能與用戶交互的,不能自己啟動的,運行在後台的程序,如果我們退出應用時,Service進程
Android UI設計之(十二)自定義View,實現絢麗的字體大小控制控件FontSliderBar
了解iOS的同學應該知道在iOS中有個UISliderBar控件,在iPhone手機中的設置文字大小中使用了該控件。近來產品提的需求中有一個是更改APP中部分字體大小,雖
安卓開發 第六篇 我的安卓應用架構設計-----BaseActivity類
BaseActivity是項目中所有activity的基類,含有一些公共的屬性和方法,同時控制toolbar的顯示,以及其他一些功能。。。來看源碼:/** * BaseA
Servlet異常處理
1:聲明式異常處理什麼是聲明式:就是在web.xml中聲明對各種異常的處理方法。是通過元素來聲明的,下面有幾個子元素如下圖error-code:http錯誤代碼excep