一诫尽、React Native常量概念
1、ReactRootView
是RN界面的最頂層的View炬守,主要負(fù)責(zé)進(jìn)行監(jiān)聽分發(fā)事件,渲染元素等工作剂跟。它可以通過監(jiān)聽View的尺寸從而使UIManager可以對(duì)其子元素進(jìn)行重新布局减途。
2、ReactInstanceManager
主要被用于管理CatalystInstance
實(shí)例對(duì)象曹洽。通過ReactPackage
鳍置,它向開發(fā)人員提供了配置和使用CatalystInstance
實(shí)例對(duì)象的方法,并對(duì)該CatalystInstance
實(shí)例的生命周期進(jìn)行追蹤送淆。ReactInstanceManager
實(shí)例對(duì)象的生命周期與ReactRootView
所在的Activity保持一致税产。
3、ReactNativeHost
一個(gè)普通的抽象類偷崩,提供一些相關(guān)的方法辟拷,主要提供ReactInstanceManager
的創(chuàng)建
4、NativeModuleRegistry
一組Java API阐斜,以暴露給特定的JavaScript實(shí)例衫冻。暴露原生方法給JS
5、CatalystInstance
異步JSC橋上的更高級(jí)API谒出。 提供了一個(gè)允許調(diào)用JavaScript方法的環(huán)境隅俘,并允許一組Java API也可以從JavaScript調(diào)用。
6笤喳、HybridData
一個(gè)持有C++層對(duì)象實(shí)例指針的Java層實(shí)例为居,負(fù)責(zé)Java層和C++層之間的數(shù)據(jù)傳輸
二、React Native啟動(dòng)流程分析
1杀狡、Application
初始化ReactNativeHost
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RNFSPackage(),
new LottiePackage(),
new AutoHeightWebViewPackage(),
new MReactPackage(),
new LinearGradientPackage(),
new CodePush(BuildConfig.CODEPUSH_KEY, SysApplication.this, BuildConfig.DEBUG),
new SvgPackage(),
new RNViewShotPackage(),
new RNSentryPackage()
);
}
@Override
protected String getJSBundleFile() {
return CodePush.getJSBundleFile();
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
2蒙畴、ReactInstanceManager
的初始化
mReactInstanceManager = ((ReactApplication) GlobalServiceManager.getService(IAppService.class).getAppContext())
.getReactNativeHost()
.getReactInstanceManager();
首先來看getReactInstanceManager()
調(diào)用了createReactInstanceManager()
,createReactInstanceManager()
中代碼如下
/**
* Get the current {@link ReactInstanceManager} instance, or create one.
*/
public ReactInstanceManager getReactInstanceManager() {
if (mReactInstanceManager == null) {
ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_START);
mReactInstanceManager = createReactInstanceManager();
ReactMarker.logMarker(ReactMarkerConstants.GET_REACT_INSTANCE_MANAGER_END);
}
return mReactInstanceManager;
}
protected ReactInstanceManager createReactInstanceManager() {
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_START);
ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
.setApplication(mApplication)
.setJSMainModulePath(getJSMainModuleName())
.setUseDeveloperSupport(getUseDeveloperSupport())
.setRedBoxHandler(getRedBoxHandler())
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
.setUIImplementationProvider(getUIImplementationProvider())
.setJSIModulesProvider(getJSIModulesProvider())
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
for (ReactPackage reactPackage : getPackages()) {
builder.addPackage(reactPackage);
}
String jsBundleFile = getJSBundleFile();
if (jsBundleFile != null) {
builder.setJSBundleFile(jsBundleFile);
} else {
builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
}
ReactInstanceManager reactInstanceManager = builder.build();
ReactMarker.logMarker(ReactMarkerConstants.BUILD_REACT_INSTANCE_MANAGER_END);
return reactInstanceManager;
}
可以看到創(chuàng)建ReactInstanceManager
的步驟是這樣的
- 創(chuàng)建
ReactInstanceManagerBuilder
對(duì)象 - 把在
ReactNativeHost
中注冊(cè)的ReactPackage
全部添加到ReactInstanceManagerBuilder
實(shí)例化對(duì)象中 - 如果
getJSBundleFile()
有在ReactNativeHost
注冊(cè)聲明則加載相應(yīng)文件捣卤,沒有則去加載默認(rèn)生成的JSBundleFile
- 調(diào)用
ReactInstanceManagerBuilder
實(shí)例對(duì)象的build()構(gòu)造實(shí)例
ReactInstanceManagerBuilder
的build()
方法如下
/**
* Instantiates a new {@link ReactInstanceManager}.
* Before calling {@code build}, the following must be called:
* <ul>
* <li> {@link #setApplication}
* <li> {@link #setCurrentActivity} if the activity has already resumed
* <li> {@link #setDefaultHardwareBackBtnHandler} if the activity has already resumed
* <li> {@link #setJSBundleFile} or {@link #setJSMainModulePath}
* </ul>
*/
public ReactInstanceManager build() {
Assertions.assertNotNull(
mApplication,
"Application property has not been set with this builder");
Assertions.assertCondition(
mUseDeveloperSupport || mJSBundleAssetUrl != null || mJSBundleLoader != null,
"JS Bundle File or Asset URL has to be provided when dev support is disabled");
Assertions.assertCondition(
mJSMainModulePath != null || mJSBundleAssetUrl != null || mJSBundleLoader != null,
"Either MainModulePath or JS Bundle File needs to be provided");
if (mUIImplementationProvider == null) {
// create default UIImplementationProvider if the provided one is null.
mUIImplementationProvider = new UIImplementationProvider();
}
// We use the name of the device and the app for debugging & metrics
String appName = mApplication.getPackageName();
String deviceName = getFriendlyDeviceName();
return new ReactInstanceManager(
mApplication,
mCurrentActivity,
mDefaultHardwareBackBtnHandler,
mJavaScriptExecutorFactory == null
? new JSCJavaScriptExecutorFactory(appName, deviceName)
: mJavaScriptExecutorFactory,
(mJSBundleLoader == null && mJSBundleAssetUrl != null)
? JSBundleLoader.createAssetLoader(
mApplication, mJSBundleAssetUrl, false /*Asynchronous*/)
: mJSBundleLoader,
mJSMainModulePath,
mPackages,
mUseDeveloperSupport,
mBridgeIdleDebugListener,
Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"),
mUIImplementationProvider,
mNativeModuleCallExceptionHandler,
mRedBoxHandler,
mLazyNativeModulesEnabled,
mLazyViewManagersEnabled,
mDelayViewManagerClassLoadsEnabled,
mDevBundleDownloadListener,
mMinNumShakes,
mMinTimeLeftInFrameForNonBatchedOperationMs,
mJSIModulesProvider);
}
這里需要注意的2個(gè)地方的初始化
mJavaScriptExecutorFactory == null
? new JSCJavaScriptExecutorFactory(appName, deviceName)
: mJavaScriptExecutorFactory,
(mJSBundleLoader == null && mJSBundleAssetUrl != null)
? JSBundleLoader.createAssetLoader(
mApplication, mJSBundleAssetUrl, false /*Asynchronous*/)
: mJSBundleLoader,
其中JSCJavaScriptExecutorFactory
是JavaScriptExecutorFactory
的實(shí)現(xiàn)忍抽,負(fù)責(zé)創(chuàng)建相應(yīng)的JavaScriptExecutor
,JSBundleLoader.createAssetLoader()
則創(chuàng)建相應(yīng)的JSBundleLoader
/**
* This loader is recommended one for release version of your app. In that case local JS executor
* should be used. JS bundle will be read from assets in native code to save on passing large
* strings from java to native memory.
*/
public static JSBundleLoader createAssetLoader(
final Context context,
final String assetUrl,
final boolean loadSynchronously) {
return new JSBundleLoader() {
@Override
public String loadScript(CatalystInstanceImpl instance) {
instance.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
return assetUrl;
}
};
}
3、ReactRootView
和JS應(yīng)用程序
的關(guān)聯(lián)
mReactRootView.startReactApplication(
mReactInstanceManager,
getMainComponentName(),
appProperties
);
ReactRootView
通過startReactApplication
方法關(guān)聯(lián)JS相應(yīng)模塊董朝,進(jìn)入startReactApplication
源碼
/**
* Schedule rendering of the react component rendered by the JS application from the given JS
* module (@{param moduleName}) using provided {@param reactInstanceManager} to attach to the
* JS context of that manager. Extra parameter {@param launchOptions} can be used to pass initial
* properties for the react component.
*/
public void startReactApplication(
ReactInstanceManager reactInstanceManager,
String moduleName,
@Nullable Bundle initialProperties) {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "startReactApplication");
try {
UiThreadUtil.assertOnUiThread();
// TODO(6788889): Use POJO instead of bundle here, apparently we can't just use WritableMap
// here as it may be deallocated in native after passing via JNI bridge, but we want to reuse
// it in the case of re-creating the catalyst instance
Assertions.assertCondition(
mReactInstanceManager == null,
"This root view has already been attached to a catalyst instance manager");
mReactInstanceManager = reactInstanceManager;
mJSModuleName = moduleName;
mAppProperties = initialProperties;
if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
mReactInstanceManager.createReactContextInBackground();
}
attachToReactInstanceManager();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
首先追蹤createReactContextInBackground()
方法,忽略Debug環(huán)境的一些初始化代碼鸠项,最后追蹤到下面這個(gè)方法
@ThreadConfined(UI)
private void recreateReactContextInBackgroundFromBundleLoader() {
Log.d(
ReactConstants.TAG,
"ReactInstanceManager.recreateReactContextInBackgroundFromBundleLoader()");
PrinterHolder.getPrinter()
.logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: load from BundleLoader");
recreateReactContextInBackground(mJavaScriptExecutorFactory, mBundleLoader);
}
這里的mJavaScriptExecutorFactory
和mBundleLoader
則是上面初始化ReactInstanceManager
時(shí)已經(jīng)構(gòu)建的,繼續(xù)追蹤recreateReactContextInBackground()
,部分代碼已省略
@ThreadConfined(UI)
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
..................
mCreateReactContextThread =
new Thread(
new Runnable() {
@Override
public void run() {
................
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
final ReactApplicationContext reactApplicationContext =
createReactContext(
initParams.getJsExecutorFactory().create(),
initParams.getJsBundleLoader());
.................
Runnable setupReactContextRunnable =
new Runnable() {
@Override
public void run() {
try {
setupReactContext(reactApplicationContext);
} catch (Exception e) {
mDevSupportManager.handleException(e);
}
}
};
reactApplicationContext.runOnNativeModulesQueueThread(setupReactContextRunnable);
UiThreadUtil.runOnUiThread(maybeRecreateReactContextRunnable);
} catch (Exception e) {
mDevSupportManager.handleException(e);
}
}
});
ReactMarker.logMarker(REACT_CONTEXT_THREAD_START);
mCreateReactContextThread.start();
}
進(jìn)入createReactContext()
里追蹤
/**
* @return instance of {@link ReactContext} configured a {@link CatalystInstance} set
*/
private ReactApplicationContext createReactContext(
JavaScriptExecutor jsExecutor,
JSBundleLoader jsBundleLoader) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.createReactContext()");
ReactMarker.logMarker(CREATE_REACT_CONTEXT_START);
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
if (mUseDeveloperSupport) {
reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
}
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
.setJSExecutor(jsExecutor)
.setRegistry(nativeModuleRegistry)
.setJSBundleLoader(jsBundleLoader)
.setNativeModuleCallExceptionHandler(exceptionHandler);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START);
// CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
final CatalystInstance catalystInstance;
try {
catalystInstance = catalystInstanceBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
}
if (mJSIModulesProvider != null) {
catalystInstance.addJSIModules(mJSIModulesProvider
.getJSIModules(reactContext, catalystInstance.getJavaScriptContextHolder()));
}
if (mBridgeIdleDebugListener != null) {
catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener);
}
if (Systrace.isTracing(TRACE_TAG_REACT_APPS | TRACE_TAG_REACT_JS_VM_CALLS)) {
catalystInstance.setGlobalVariable("__RCTProfileIsProfiling", "true");
}
ReactMarker.logMarker(ReactMarkerConstants.PRE_RUN_JS_BUNDLE_START);
catalystInstance.runJSBundle();
reactContext.initializeWithInstance(catalystInstance);
return reactContext;
}
這個(gè)方法里主要做了這幾件事情
- 創(chuàng)建
ReactApplicationContext
實(shí)例 - 創(chuàng)建
NativeModuleRegistry
- 創(chuàng)建
CatalystInstance
- 執(zhí)行JS端代碼初始化
- 初始化
ReactApplicationContext
實(shí)例的mCatalystInstance
對(duì)象
(1)NativeModuleRegistry
的創(chuàng)建主要看一下NativeModuleRegistryBuilder
的創(chuàng)建代碼
public void processPackage(ReactPackage reactPackage) {
if (mLazyNativeModulesEnabled) {
if (!(reactPackage instanceof LazyReactPackage)) {
throw new IllegalStateException("Lazy native modules requires all ReactPackage to " +
"inherit from LazyReactPackage");
}
LazyReactPackage lazyReactPackage = (LazyReactPackage) reactPackage;
List<ModuleSpec> moduleSpecs = lazyReactPackage.getNativeModules(mReactApplicationContext);
Map<Class, ReactModuleInfo> reactModuleInfoMap = lazyReactPackage.getReactModuleInfoProvider()
.getReactModuleInfos();
for (ModuleSpec moduleSpec : moduleSpecs) {
Class<? extends NativeModule> type = moduleSpec.getType();
ReactModuleInfo reactModuleInfo = reactModuleInfoMap.get(type);
ModuleHolder moduleHolder;
if (reactModuleInfo == null) {
if (BaseJavaModule.class.isAssignableFrom(type)) {
throw new IllegalStateException("Native Java module " + type.getSimpleName() +
" should be annotated with @ReactModule and added to a @ReactModuleList.");
}
NativeModule module;
ReactMarker.logMarker(
ReactMarkerConstants.CREATE_MODULE_START,
moduleSpec.getType().getName());
try {
module = moduleSpec.getProvider().get();
} finally {
ReactMarker.logMarker(ReactMarkerConstants.CREATE_MODULE_END);
}
moduleHolder = new ModuleHolder(module);
} else {
moduleHolder = new ModuleHolder(reactModuleInfo, moduleSpec.getProvider());
}
String name = moduleHolder.getName();
if (namesToType.containsKey(name)) {
Class<? extends NativeModule> existingNativeModule = namesToType.get(name);
if (!moduleHolder.getCanOverrideExistingModule()) {
throw new IllegalStateException("Native module " + type.getSimpleName() +
" tried to override " + existingNativeModule.getSimpleName() + " for module name " +
name + ". If this was your intention, set canOverrideExistingModule=true");
}
mModules.remove(existingNativeModule);
}
namesToType.put(name, type);
mModules.put(type, moduleHolder);
}
} else {
FLog.d(
ReactConstants.TAG,
reactPackage.getClass().getSimpleName() +
" is not a LazyReactPackage, falling back to old version.");
List<NativeModule> nativeModules;
if (reactPackage instanceof ReactInstancePackage) {
ReactInstancePackage reactInstancePackage = (ReactInstancePackage) reactPackage;
nativeModules = reactInstancePackage.createNativeModules(
mReactApplicationContext,
mReactInstanceManager);
} else {
nativeModules = reactPackage.createNativeModules(mReactApplicationContext);
}
for (NativeModule nativeModule : nativeModules) {
addNativeModule(nativeModule);
}
}
}
分為2種加載模式子姜,懶加載和正常加載祟绊。最后都是把在ReactNativeHost
中注冊(cè)的ReactPackage
放入一個(gè)Map映射內(nèi)
public void addNativeModule(NativeModule nativeModule) {
String name = nativeModule.getName();
Class<? extends NativeModule> type = nativeModule.getClass();
if (namesToType.containsKey(name)) {
Class<? extends NativeModule> existingModule = namesToType.get(name);
if (!nativeModule.canOverrideExistingModule()) {
throw new IllegalStateException("Native module " + type.getSimpleName() +
" tried to override " + existingModule.getSimpleName() + " for module name " +
name + ". If this was your intention, set canOverrideExistingModule=true");
}
mModules.remove(existingModule);
}
namesToType.put(name, type);
ModuleHolder moduleHolder = new ModuleHolder(nativeModule);
mModules.put(type, moduleHolder);
}
然后調(diào)用build()
方法構(gòu)建NativeModuleRegistry
public NativeModuleRegistry build() {
ArrayList<ModuleHolder> batchCompleteListenerModules = new ArrayList<>();
for (Map.Entry<Class<? extends NativeModule>, ModuleHolder> entry : mModules.entrySet()) {
if (OnBatchCompleteListener.class.isAssignableFrom(entry.getKey())) {
batchCompleteListenerModules.add(entry.getValue());
}
}
return new NativeModuleRegistry(
mReactApplicationContext,
mModules,
batchCompleteListenerModules);
}
(2)CatalystInstance
實(shí)例的創(chuàng)建
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
.setJSExecutor(jsExecutor)
.setRegistry(nativeModuleRegistry)
.setJSBundleLoader(jsBundleLoader)
.setNativeModuleCallExceptionHandler(exceptionHandler);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START);
// CREATE_CATALYST_INSTANCE_END is in JSCExecutor.cpp
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance");
final CatalystInstance catalystInstance;
try {
catalystInstance = catalystInstanceBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
}
追蹤CatalystInstanceImpl
實(shí)例的初始化過程楼入,這邊則是重點(diǎn),實(shí)現(xiàn)了Java端和C++的關(guān)聯(lián)
private CatalystInstanceImpl(
final ReactQueueConfigurationSpec reactQueueConfigurationSpec,
final JavaScriptExecutor jsExecutor,
final NativeModuleRegistry nativeModuleRegistry,
final JSBundleLoader jsBundleLoader,
NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) {
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge.");
mHybridData = initHybrid();
mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
reactQueueConfigurationSpec,
new NativeExceptionHandler());
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
mNativeModuleRegistry = nativeModuleRegistry;
mJSModuleRegistry = new JavaScriptModuleRegistry();
mJSBundleLoader = jsBundleLoader;
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
mTraceListener = new JSProfilerTraceListener(this);
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge before initializeBridge");
initializeBridge(
new BridgeCallback(this),
jsExecutor,
mReactQueueConfiguration.getJSQueueThread(),
mNativeModulesQueueThread,
mNativeModuleRegistry.getJavaModules(this),
mNativeModuleRegistry.getCxxModules());
Log.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
mJavaScriptContextHolder = new JavaScriptContextHolder(getJavaScriptContext());
}
主要就是下面的2個(gè)方法
private native static HybridData initHybrid();
初始化HybridData牧抽,使得Java對(duì)象持有C++對(duì)象的指針
private native void initializeBridge(
ReactCallback callback,
JavaScriptExecutor jsExecutor,
MessageQueueThread jsQueue,
MessageQueueThread moduleQueue,
Collection<JavaModuleWrapper> javaModules,
Collection<ModuleHolder> cxxModules);
初始化Java端和C++的橋
如果追蹤C(jī)++層代碼嘉熊,可以發(fā)現(xiàn)以下代碼,具體的初始化過程這里不再深入
void CatalystInstanceImpl::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", CatalystInstanceImpl::initHybrid),
makeNativeMethod("initializeBridge", CatalystInstanceImpl::initializeBridge),
makeNativeMethod("jniExtendNativeModules", CatalystInstanceImpl::extendNativeModules),
makeNativeMethod("jniSetSourceURL", CatalystInstanceImpl::jniSetSourceURL),
makeNativeMethod("jniRegisterSegment", CatalystInstanceImpl::jniRegisterSegment),
makeNativeMethod("jniLoadScriptFromAssets", CatalystInstanceImpl::jniLoadScriptFromAssets),
makeNativeMethod("jniLoadScriptFromFile", CatalystInstanceImpl::jniLoadScriptFromFile),
makeNativeMethod("jniLoadScriptFromDeltaBundle", CatalystInstanceImpl::jniLoadScriptFromDeltaBundle),
makeNativeMethod("jniCallJSFunction", CatalystInstanceImpl::jniCallJSFunction),
makeNativeMethod("jniCallJSCallback", CatalystInstanceImpl::jniCallJSCallback),
makeNativeMethod("setGlobalVariable", CatalystInstanceImpl::setGlobalVariable),
makeNativeMethod("getJavaScriptContext", CatalystInstanceImpl::getJavaScriptContext),
makeNativeMethod("jniHandleMemoryPressure", CatalystInstanceImpl::handleMemoryPressure),
});
JNativeRunnable::registerNatives();
}
映射initHybrid
到CatalystInstanceImpl.cpp
類中的initHybrid
方法扬舒,映射initializeBridge
到CatalystInstanceImpl.cpp
的initializeBridge
方法阐肤,如果有興趣的同學(xué)可以下載React Native
源碼才開ReactAndroid NDK
部分。
關(guān)于通訊數(shù)據(jù)模型可以參考這篇文章讲坎,本文不再贅述孕惜。React-Native系列Android——通信數(shù)據(jù)模型分析
(3)執(zhí)行JS端的初始化
JS端代碼初始化調(diào)用CatalystInstance
實(shí)例的runJSBundle()方法
@Override
public void runJSBundle() {
Log.d(ReactConstants.TAG, "CatalystInstanceImpl.runJSBundle()");
Assertions.assertCondition(!mJSBundleHasLoaded, "JS bundle was already loaded!");
// incrementPendingJSCalls();
mJSBundleLoader.loadScript(CatalystInstanceImpl.this);
synchronized (mJSCallsPendingInitLock) {
// Loading the bundle is queued on the JS thread, but may not have
// run yet. It's safe to set this here, though, since any work it
// gates will be queued on the JS thread behind the load.
mAcceptCalls = true;
for (PendingJSCall function : mJSCallsPendingInit) {
function.call(this);
}
mJSCallsPendingInit.clear();
mJSBundleHasLoaded = true;
}
// This is registered after JS starts since it makes a JS call
Systrace.registerListener(mTraceListener);
}
可以看到這邊調(diào)用了mJSBundleLoader
的loadScript
方法,而這個(gè)方法在初始化ReactInstanceManager
調(diào)用了JSBundleLoader.createAssetLoader
進(jìn)行了實(shí)現(xiàn)。
/**
* This loader is recommended one for release version of your app. In that case local JS executor
* should be used. JS bundle will be read from assets in native code to save on passing large
* strings from java to native memory.
*/
public static JSBundleLoader createAssetLoader(
final Context context,
final String assetUrl,
final boolean loadSynchronously) {
return new JSBundleLoader() {
@Override
public String loadScript(CatalystInstanceImpl instance) {
instance.loadScriptFromAssets(context.getAssets(), assetUrl, loadSynchronously);
return assetUrl;
}
};
}
繼續(xù)追蹤可以發(fā)現(xiàn)這邊調(diào)用了C++層的代碼初始化
private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
(4)初始化ReactApplicationContext
實(shí)例的mCatalystInstance
對(duì)象
/**
* Set and initialize CatalystInstance for this Context. This should be called exactly once.
*/
public void initializeWithInstance(CatalystInstance catalystInstance) {
if (catalystInstance == null) {
throw new IllegalArgumentException("CatalystInstance cannot be null.");
}
if (mCatalystInstance != null) {
throw new IllegalStateException("ReactContext has been already initialized");
}
mCatalystInstance = catalystInstance;
ReactQueueConfiguration queueConfig = catalystInstance.getReactQueueConfiguration();
mUiMessageQueueThread = queueConfig.getUIQueueThread();
mNativeModulesMessageQueueThread = queueConfig.getNativeModulesQueueThread();
mJSMessageQueueThread = queueConfig.getJSQueueThread();
}
到這里只是分析了createReactContext()
方法里所做的事情晨炕,createReactContext()
最后返回了ReactApplicationContext
的實(shí)例化對(duì)象衫画。而這個(gè)實(shí)例化對(duì)象被setupReactContext()
所調(diào)用,進(jìn)一步追蹤源碼
private void setupReactContext(final ReactApplicationContext reactContext) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.setupReactContext()");
ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_END);
ReactMarker.logMarker(SETUP_REACT_CONTEXT_START);
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "setupReactContext");
synchronized (mReactContextLock) {
mCurrentReactContext = Assertions.assertNotNull(reactContext);
}
CatalystInstance catalystInstance =
Assertions.assertNotNull(reactContext.getCatalystInstance());
catalystInstance.initialize();
mDevSupportManager.onNewReactContextCreated(reactContext);
mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);
moveReactContextToCurrentLifecycleState();
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START);
synchronized (mAttachedRootViews) {
for (ReactRootView rootView : mAttachedRootViews) {
attachRootViewToInstance(rootView, catalystInstance);
}
}
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END);
ReactInstanceEventListener[] listeners =
new ReactInstanceEventListener[mReactInstanceEventListeners.size()];
final ReactInstanceEventListener[] finalListeners =
mReactInstanceEventListeners.toArray(listeners);
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
for (ReactInstanceEventListener listener : finalListeners) {
listener.onReactContextInitialized(reactContext);
}
}
});
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(SETUP_REACT_CONTEXT_END);
reactContext.runOnJSQueueThread(
new Runnable() {
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
}
});
reactContext.runOnNativeModulesQueueThread(
new Runnable() {
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
}
});
}
這個(gè)方法主要做了這些事情
- 所有原生模塊的初始化
- 繪制所有的
RootView
并添加到相應(yīng)實(shí)例并設(shè)置相應(yīng)的監(jiān)聽事件 - 添加
CatalystInstance
實(shí)例的內(nèi)存監(jiān)聽事件 - 設(shè)置
React
所有相關(guān)實(shí)例初始化完成之后的監(jiān)聽 - 設(shè)置JS模塊和原生模塊所在線程的優(yōu)先級(jí)
(1) 所有原生模塊的初始化
CatalystInstance catalystInstance =
Assertions.assertNotNull(reactContext.getCatalystInstance());
catalystInstance.initialize();
追蹤initialize()
方法
/**
* Initialize all the native modules
*/
@VisibleForTesting
@Override
public void initialize() {
Log.d(ReactConstants.TAG, "CatalystInstanceImpl.initialize()");
Assertions.assertCondition(
!mInitialized,
"This catalyst instance has already been initialized");
// We assume that the instance manager blocks on running the JS bundle. If
// that changes, then we need to set mAcceptCalls just after posting the
// task that will run the js bundle.
Assertions.assertCondition(
mAcceptCalls,
"RunJSBundle hasn't completed.");
mInitialized = true;
mNativeModulesQueueThread.runOnQueue(new Runnable() {
@Override
public void run() {
mNativeModuleRegistry.notifyJSInstanceInitialized();
}
});
}
/* package */ void notifyJSInstanceInitialized() {
mReactApplicationContext.assertOnNativeModulesQueueThread("From version React Native v0.44, " +
"native modules are explicitly not initialized on the UI thread. See " +
"https://github.com/facebook/react-native/wiki/Breaking-Changes#d4611211-reactnativeandroidbreaking-move-nativemodule-initialization-off-ui-thread---aaachiuuu " +
" for more details.");
ReactMarker.logMarker(ReactMarkerConstants.NATIVE_MODULE_INITIALIZE_START);
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"NativeModuleRegistry_notifyJSInstanceInitialized");
try {
for (ModuleHolder module : mModules.values()) {
module.markInitializable();
}
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(ReactMarkerConstants.NATIVE_MODULE_INITIALIZE_END);
}
}
(2)繪制所有的RootView
并添加到相應(yīng)實(shí)例并設(shè)置相應(yīng)的監(jiān)聽事件
synchronized (mAttachedRootViews) {
for (ReactRootView rootView : mAttachedRootViews) {
attachRootViewToInstance(rootView, catalystInstance);
}
}
這里的mAttachedRootViews
在startReactApplication()
方法中attachToReactInstanceManager()
中初始化瓮栗。
public void startReactApplication(
ReactInstanceManager reactInstanceManager,
String moduleName,
@Nullable Bundle initialProperties) {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "startReactApplication");
try {
.............................
if (!mReactInstanceManager.hasStartedCreatingInitialContext()) {
mReactInstanceManager.createReactContextInBackground();
}
attachToReactInstanceManager();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
追蹤attachToReactInstanceManager()
方法,可以看到mAttachedRootViews
是在這里add的
private void attachToReactInstanceManager() {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachToReactInstanceManager");
try {
if (mIsAttachedToInstance) {
return;
}
mIsAttachedToInstance = true;
Assertions.assertNotNull(mReactInstanceManager).attachRootView(this);
getViewTreeObserver().addOnGlobalLayoutListener(getCustomGlobalLayoutListener());
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
/**
* Attach given {@param rootView} to a catalyst instance manager and start JS application using
* JS module provided by {@link ReactRootView#getJSModuleName}. If the react context is currently
* being (re)-created, or if react context has not been created yet, the JS application associated
* with the provided root view will be started asynchronously, i.e this method won't block.
* This view will then be tracked by this manager and in case of catalyst instance restart it will
* be re-attached.
*/
@ThreadConfined(UI)
public void attachRootView(ReactRootView rootView) {
UiThreadUtil.assertOnUiThread();
mAttachedRootViews.add(rootView);
// Reset view content as it's going to be populated by the application content from JS.
rootView.removeAllViews();
rootView.setId(View.NO_ID);
// If react context is being created in the background, JS application will be started
// automatically when creation completes, as root view is part of the attached root view list.
ReactContext currentContext = getCurrentReactContext();
if (mCreateReactContextThread == null && currentContext != null) {
attachRootViewToInstance(rootView, currentContext.getCatalystInstance());
}
}
由于createReactContextInBackground()
里的代碼通過上面的源碼分析是在一個(gè)單獨(dú)的線程里執(zhí)行削罩,而加載JS端和讀取JSBundle
文件都比較耗時(shí),所以mAttachedRootViews
并不會(huì)為空费奸,attachRootViewToInstance()
一定會(huì)被執(zhí)行弥激,繼續(xù)追蹤attachRootViewToInstance()
方法。
private void attachRootViewToInstance(
final ReactRootView rootView,
CatalystInstance catalystInstance) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.attachRootViewToInstance()");
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "attachRootViewToInstance");
UIManager uiManagerModule = rootView.isFabric() ? catalystInstance.getJSIModule(UIManager.class) : catalystInstance.getNativeModule(UIManagerModule.class);
final int rootTag = uiManagerModule.addRootView(rootView);
rootView.setRootViewTag(rootTag);
rootView.invokeJSEntryPoint();
Systrace.beginAsyncSection(
TRACE_TAG_REACT_JAVA_BRIDGE,
"pre_rootView.onAttachedToReactInstance",
rootTag);
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
Systrace.endAsyncSection(
TRACE_TAG_REACT_JAVA_BRIDGE,
"pre_rootView.onAttachedToReactInstance",
rootTag);
rootView.onAttachedToReactInstance();
}
});
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
這個(gè)方法比較關(guān)鍵的幾行代碼如下
UIManager uiManagerModule = rootView.isFabric() ? catalystInstance.getJSIModule(UIManager.class) : catalystInstance.getNativeModule(UIManagerModule.class);
final int rootTag = uiManagerModule.addRootView(rootView);
rootView.setRootViewTag(rootTag);
rootView.invokeJSEntryPoint();
- 獲取
UIManager
愿阐,開始測(cè)量RootView
秆撮、給RootView
設(shè)置布局監(jiān)聽、把RootView
加入UIViewOperationQueue
主隊(duì)列 - 設(shè)置
RootView
的RootViewTag
- 調(diào)用JS端入口函數(shù)换况,執(zhí)行JS端代碼
首先我們追蹤invokeJSEntryPoint()
方法,可以發(fā)現(xiàn)這個(gè)方法
/**
* Calls the default entry point into JS which is AppRegistry.runApplication()
*/
private void defaultJSEntryPoint() {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactRootView.runApplication");
try {
if (mReactInstanceManager == null || !mIsAttachedToInstance) {
return;
}
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
return;
}
CatalystInstance catalystInstance = reactContext.getCatalystInstance();
WritableNativeMap appParams = new WritableNativeMap();
appParams.putDouble("rootTag", getRootViewTag());
@Nullable Bundle appProperties = getAppProperties();
if (appProperties != null) {
appParams.putMap("initialProps", Arguments.fromBundle(appProperties));
}
mShouldLogContentAppeared = true;
String jsAppModuleName = getJSModuleName();
catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
這里則調(diào)用JS端入口函數(shù)职辨,執(zhí)行JS端代碼,再來追蹤UIManager
的addRootView()
方法
/**
* Registers a new root view. JS can use the returned tag with manageChildren to add/remove
* children to this view.
*
* <p>Note that this must be called after getWidth()/getHeight() actually return something. See
* CatalystApplicationFragment as an example.
*
* <p>TODO(6242243): Make addRootView thread safe NB: this method is horribly not-thread-safe.
*/
@Override
public <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> int addRootView(
final T rootView) {
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"UIManagerModule.addRootView");
final int tag = ReactRootViewTagGenerator.getNextRootViewTag();
final ReactApplicationContext reactApplicationContext = getReactApplicationContext();
final ThemedReactContext themedRootContext =
new ThemedReactContext(reactApplicationContext, rootView.getContext());
mUIImplementation.registerRootView(rootView, tag, themedRootContext);
rootView.setOnSizeChangedListener(
new SizeMonitoringFrameLayout.OnSizeChangedListener() {
@Override
public void onSizeChanged(final int width, final int height, int oldW, int oldH) {
reactApplicationContext.runOnNativeModulesQueueThread(
new GuardedRunnable(reactApplicationContext) {
@Override
public void runGuarded() {
updateNodeSize(tag, width, height);
}
});
}
});
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
return tag;
}
/**
* Registers a root node with a given tag, size and ThemedReactContext and adds it to a node
* registry.
*/
public <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> void registerRootView(
T rootView, int tag, ThemedReactContext context) {
final ReactShadowNode rootCSSNode = createRootShadowNode();
rootCSSNode.setReactTag(tag);
rootCSSNode.setThemedContext(context);
int widthMeasureSpec = rootView.getWidthMeasureSpec();
int heightMeasureSpec = rootView.getHeightMeasureSpec();
updateRootView(rootCSSNode, widthMeasureSpec, heightMeasureSpec);
mShadowNodeRegistry.addRootNode(rootCSSNode);
// register it within NativeViewHierarchyManager
mOperationsQueue.addRootView(tag, rootView, context);
}
到了這里RootView
已經(jīng)被加入了UIViewOperationQueue
,我們進(jìn)而進(jìn)入UIViewOperationQueue
源碼查看戈二,發(fā)現(xiàn)有很多關(guān)于視圖更新的方法舒裤。而這邊所有的方法都不會(huì)在這邊直接調(diào)用,需要要通過JS端繪制觉吭,然后進(jìn)一步通知C++端腾供,C++調(diào)用UIManagerModule
中的方法對(duì)視圖進(jìn)行刷新、移除鲜滩、創(chuàng)建伴鳖、新增等操作。我們追蹤一個(gè)UIManagerModule
創(chuàng)建視圖的方法
@ReactMethod
public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
if (DEBUG) {
String message =
"(UIManager.createView) tag: " + tag + ", class: " + className + ", props: " + props;
FLog.d(ReactConstants.TAG, message);
PrinterHolder.getPrinter().logMessage(ReactDebugOverlayTags.UI_MANAGER, message);
}
mUIImplementation.createView(tag, className, rootViewTag, props);
}
可以看到這里有一個(gè)rootViewTag
而這個(gè)rootViewTag
就是之前設(shè)置的RootView的tag徙硅,繼續(xù)追蹤代碼榜聂,可以看到這一個(gè)方法
/**
* Handles a createView call. May or may not actually create a native view.
*/
public void handleCreateView(
ReactShadowNode node,
ThemedReactContext themedContext,
@Nullable ReactStylesDiffMap initialProps) {
if (!ENABLED) {
int tag = node.getReactTag();
mUIViewOperationQueue.enqueueCreateView(
themedContext,
tag,
node.getViewClass(),
initialProps);
return;
}
boolean isLayoutOnly = node.getViewClass().equals(ViewProps.VIEW_CLASS_NAME) &&
isLayoutOnlyAndCollapsable(initialProps);
node.setIsLayoutOnly(isLayoutOnly);
if (!isLayoutOnly) {
mUIViewOperationQueue.enqueueCreateView(
themedContext,
node.getReactTag(),
node.getViewClass(),
initialProps);
}
}
在隊(duì)列中創(chuàng)建一個(gè)CreateViewOperation
任務(wù)
public void enqueueCreateView(
ThemedReactContext themedContext,
int viewReactTag,
String viewClassName,
@Nullable ReactStylesDiffMap initialProps) {
synchronized (mNonBatchedOperationsLock) {
mNonBatchedOperations.addLast(
new CreateViewOperation(
themedContext,
viewReactTag,
viewClassName,
initialProps));
}
}
查看CreateViewOperation
源碼
private final class CreateViewOperation extends ViewOperation {
private final ThemedReactContext mThemedContext;
private final String mClassName;
private final @Nullable ReactStylesDiffMap mInitialProps;
public CreateViewOperation(
ThemedReactContext themedContext,
int tag,
String className,
@Nullable ReactStylesDiffMap initialProps) {
super(tag);
mThemedContext = themedContext;
mClassName = className;
mInitialProps = initialProps;
Systrace.startAsyncFlow(Systrace.TRACE_TAG_REACT_VIEW, "createView", mTag);
}
@Override
public void execute() {
Systrace.endAsyncFlow(Systrace.TRACE_TAG_REACT_VIEW, "createView", mTag);
mNativeViewHierarchyManager.createView(
mThemedContext,
mTag,
mClassName,
mInitialProps);
}
}
繼續(xù)追蹤mNativeViewHierarchyManager
的createView()
方法
public synchronized void createView(
ThemedReactContext themedContext,
int tag,
String className,
@Nullable ReactStylesDiffMap initialProps) {
UiThreadUtil.assertOnUiThread();
SystraceMessage.beginSection(
Systrace.TRACE_TAG_REACT_VIEW,
"NativeViewHierarchyManager_createView")
.arg("tag", tag)
.arg("className", className)
.flush();
try {
ViewManager viewManager = mViewManagers.get(className);
View view = viewManager.createView(themedContext, mJSResponderHandler);
mTagsToViews.put(tag, view);
mTagsToViewManagers.put(tag, viewManager);
// Use android View id field to store React tag. This is possible since we don't inflate
// React views from layout xmls. Thus it is easier to just reuse that field instead of
// creating another (potentially much more expensive) mapping from view to React tag
view.setId(tag);
if (initialProps != null) {
viewManager.updateProperties(view, initialProps);
}
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_VIEW);
}
}
可以看著這里進(jìn)行了視圖的真正的新建疹启,并且標(biāo)記視圖的tag旬渠,后期根據(jù)這個(gè)tag來更新此視圖。