React Native 啟動(dòng)流程詳細(xì)解析
導(dǎo)讀:本文以 react-native-cli 創(chuàng)建的示例工程(安卓部分)為例,分析 React Native 的啟動(dòng)流程。
工程創(chuàng)建步驟可以參考官網(wǎng)。本文所分析 React Native 版本為 v0.64.2。
我們知道上述工程是一個(gè)安卓應(yīng)用,打開 android/ 目錄下源碼文件,首先發(fā)現(xiàn)它創(chuàng)建了兩個(gè) java 文件:MainApplication.java 和 MainActivity.java,分別做了應(yīng)用以及主 Activity 的定義。
安卓應(yīng)用的啟動(dòng)流程是:在啟動(dòng)第一個(gè) activity 之前會(huì)創(chuàng)建一個(gè)全局唯一的 Application 對(duì)象。故在此我們先分析 MainApplication
MainApplication
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// 其它對(duì) packages 的操作
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
}
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
MainApplication 繼承自 Application 類,并且實(shí)現(xiàn)了 ReactApplication 接口。在其中做的事情有:
1.創(chuàng)建成員變量 ReactNativeHost 的實(shí)例,并在創(chuàng)建過程中通過重寫 ReactNativeHost 類方法的方式,注入一些配置,包括:
- getUseDeveloperSupport: 配置是否開啟調(diào)試
- getPackages: 配置要加載的模塊
- getJSMainModuleName: 配置 js 模塊的入口文件名
2.在 onCreate 中:
- 調(diào)用 Soloader 庫。
Soloader是 facebook 推出的一個(gè) so 文件加載庫,它能夠處理 so 文件的依賴在 react-native 中,所有框架相關(guān)的 so 文件都是通過SoLoader完成加載的 - 通過
ReactInstanceManager初始化 Flipper。Flipper是 facebook 推出的用于 debug ios、Android、React Native 應(yīng)用的工具。
在這里簡(jiǎn)要介紹下 ReactNativeHost 和 ReactInstanceManager
ReactNativeHost
ReactNativeHost 是個(gè)抽象類,開發(fā)者可以重寫其中的方法,其主要的作用是:在 application 中指定一些賦值操作,進(jìn)而獲取 ReactInstanceManager 的實(shí)例。所以可以把 ReactNativeHost 作為將用戶自定義的參數(shù)賦值到 ReactInstanceManager 實(shí)例的中轉(zhuǎn)站。核心方法是: getReactInstanceManager,詳細(xì)分析見下文。
ReactInstanceManager
該類為核心類,主要負(fù)責(zé)管理 JS 的加載、維護(hù)生命周期、管理 JS 與 C++ 的交互等等。可以把 ReactInstanceManager 理解成 JS 與 C++ 的中轉(zhuǎn)橋梁。
MainActivity
接著看 MainActivity.java:
public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
return "myProject";
}
}
MainActivity 類中僅重寫了 getMainComponentName 方法。該類繼承自 ReactActivity,我們?cè)賮砜雌?ReactActivity。
public abstract class ReactActivity extends AppCompatActivity
implements DefaultHardwareBackBtnHandler, PermissionAwareActivity {
private final ReactActivityDelegate mDelegate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDelegate.onCreate(savedInstanceState);
}
ReactActivity 全權(quán)委托給 ReactActivityDelegate 來處理 onCreate 生命周期。來看 ReactActivityDelegate 的 onCreate。
protected void onCreate(Bundle savedInstanceState) {
String mainComponentName = getMainComponentName();
mReactDelegate =
new ReactDelegate(
getPlainActivity(), getReactNativeHost(), mainComponentName, getLaunchOptions()) {
@Override
protected ReactRootView createRootView() {
return ReactActivityDelegate.this.createRootView();
}
};
if (mMainComponentName != null) {
loadApp(mainComponentName);
}
}
這里首先創(chuàng)建了 ReactDelegate 實(shí)例。接著來看 loadApp 方法:
protected void loadApp(String appKey) {
mReactDelegate.loadApp(appKey);
getPlainActivity().setContentView(mReactDelegate.getReactRootView());
}
由此走到 ReactDelegate 實(shí)例的 loadApp 方法:
public void loadApp(String appKey) {
if (mReactRootView != null) {
throw new IllegalStateException("Cannot loadApp while app is already running.");
}
mReactRootView = createRootView();
mReactRootView.startReactApplication(
getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
}
在這里做了三件事:創(chuàng)建 rootView (createRootView)、創(chuàng)建 ReactInstanceManager (getReactInstanceManager)、創(chuàng)建 ReactApplication (startReactApplication)。
createRootView
首先看下什么是 rootView。
public class ReactRootView extends FrameLayout implements RootView, ReactRoot { /* ... */}
ReactRootView 繼承自 FrameLayout,并且實(shí)現(xiàn)了 RootView、ReactRoot 兩個(gè)接口。FrameLayout 是安卓幾大布局中較為簡(jiǎn)單的一個(gè),整個(gè)界面被當(dāng)成一塊空白備用區(qū)域,所有元素以左上角對(duì)齊堆疊。ReactRootView 繼承自 FrameLayout,表明其也是作為簡(jiǎn)單布局而存在,UI 的繪制渲染都發(fā)生在上面。
getReactInstanceManager
ReactInstanceManager 是一個(gè)核心類,管理著 JS 的加載、C++ 和 JS 的交互、初始化參數(shù)等。最終調(diào)用來到 ReactNativeHost 類中的 createReactInstanceManager 方法:
protected ReactInstanceManager createReactInstanceManager() {
ReactInstanceManagerBuilder builder = /* ... */
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();
return reactInstanceManager;
}
此處做的事情如下:
- 創(chuàng)建
ReactInstanceManagerBuilder實(shí)例。這里采用建造者模式來構(gòu)造ReactInstanceManager實(shí)例,故在此先傳入?yún)?shù)設(shè)定構(gòu)造者; - 把在
ReactNativeHost中注冊(cè)的packages都添加到ReactInstanceManagerBuilder實(shí)例中; - 如果
getJSBundleFile不為空,則加載對(duì)應(yīng)的文件,否則加載默認(rèn)的jsBundleFile; - 調(diào)用
builder.build方法。通過建造者真正構(gòu)造ReactInstanceManager實(shí)例
startReactApplication
public void startReactApplication(/* */) {
// ...
try {
// ...
mReactInstanceManager.createReactContextInBackground();
} finally {
// ...
}
}
最終執(zhí)行到 ReactInstanceManager 的 createReactContextInBackground 方法中。最后經(jīng)過調(diào)用鏈:recreateReactContextInBackgroundInner() -> recreateReactContextInBackgroundFromBundleLoader() -> recreateReactContextInBackground() -> runCreateReactContextOnNewThread()
runCreateReactContextOnNewThread 主要做了兩件事:
- 創(chuàng)建一個(gè)新的線程,并在新線程中通過
createReactContext創(chuàng)建ReactContext上下文; - 通過
setupReactContext來設(shè)置上下文環(huán)境,并最終調(diào)用到AppRegistry.js啟動(dòng)App。
詳細(xì)分析我們放到另一篇文章:React Native startReactApplication 流程梳理。
總結(jié)
總結(jié)本文,通過 react-native-cli 創(chuàng)建的示例工程(安卓部分)為例,順著兩個(gè)類 MainApplication 和 MainActivity 的執(zhí)行流程,抓住主干邏輯,最終梳理出了 React Native 從開始啟動(dòng)至執(zhí)行用戶 js 文件的過程??梢钥吹剑?/p>
MainApplication 的作用主要是傳入用戶的配置,并做 so 庫以及應(yīng)用 debug 工具的初始化工作;
MainActivity 的作用主要是:
- 為應(yīng)用創(chuàng)建
rootView布局容器; - 創(chuàng)建
ReactInstanceManager核心類,用于后續(xù)管理 JS 的加載、C++ 和 JS 的交互、初始化參數(shù)等; - 通過
startReactApplication來創(chuàng)建ReactContext上下文,并最終調(diào)用到AppRegistry.js啟動(dòng)App。
到此這篇關(guān)于React Native 啟動(dòng)流程簡(jiǎn)析的文章就介紹到這了,更多相關(guān)React Native 啟動(dòng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于React中setState同步或異步問題的理解
相信很多小伙伴們都一直在疑惑,setState 到底是同步還是異步。本文就詳細(xì)的介紹一下React中setState同步或異步問題,感興趣的可以了解一下2021-11-11
ReactNative頁面跳轉(zhuǎn)Navigator實(shí)現(xiàn)的示例代碼
本篇文章主要介紹了ReactNative頁面跳轉(zhuǎn)Navigator實(shí)現(xiàn)的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08
React 數(shù)據(jù)獲取條件競(jìng)爭(zhēng)原理解析
這篇文章主要為大家介紹了React 數(shù)據(jù)獲取條件競(jìng)爭(zhēng)原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
react antd如何防止一份數(shù)據(jù)多次提交
這篇文章主要介紹了react antd如何防止一份數(shù)據(jù)多次提交問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10
react實(shí)現(xiàn)復(fù)選框全選和反選組件效果
這篇文章主要為大家詳細(xì)介紹了react實(shí)現(xiàn)復(fù)選框全選和反選組件效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08
詳解在React項(xiàng)目中如何集成和使用web worker
在復(fù)雜的React應(yīng)用中,某些計(jì)算密集型或耗時(shí)操作可能會(huì)阻塞主線程,導(dǎo)致用戶界面出現(xiàn)卡頓或響應(yīng)慢的現(xiàn)象,為了優(yōu)化用戶體驗(yàn),可以采用Web Worker來在后臺(tái)線程中執(zhí)行這些操作,本文將詳細(xì)介紹在React項(xiàng)目中如何集成和使用Web Worker來改善應(yīng)用性能,需要的朋友可以參考下2023-12-12
React操作真實(shí)DOM實(shí)現(xiàn)動(dòng)態(tài)吸底部的示例
本篇文章主要介紹了React操作真實(shí)DOM實(shí)現(xiàn)動(dòng)態(tài)吸底部的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10
react中使用redux-persist做持久化儲(chǔ)存的過程記錄
這篇文章主要介紹了react中使用redux-persist做持久化儲(chǔ)存的相關(guān)資料,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-01-01
React父組件數(shù)據(jù)實(shí)時(shí)更新了,子組件沒有更新的問題
這篇文章主要介紹了React父組件數(shù)據(jù)實(shí)時(shí)更新了,子組件沒有更新的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03

