本篇內容介紹了“React Native啟動流程是怎樣的”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
導讀:本文以 react-native-cli 創建的示例工程(安卓部分)為例,分析 React Native 的啟動流程。
工程創建步驟可以參考官網。本文所分析 React Native 版本為 v0.64.2。
我們知道上述工程是一個安卓應用,打開 android/ 目錄下源碼文件,首先發現它創建了兩個 java 文件:MainApplication.java 和 MainActivity.java,分別做了應用以及主 Activity 的定義。
安卓應用的啟動流程是:在啟動第一個 activity 之前會創建一個全局唯一的 Application 對象。故在此我們先分析 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();
// 其它對 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 類,并且實現了 ReactApplication 接口。在其中做的事情有:
1.創建成員變量 ReactNativeHost 的實例,并在創建過程中通過重寫 ReactNativeHost 類方法的方式,注入一些配置,包括:
getUseDeveloperSupport: 配置是否開啟調試
getPackages: 配置要加載的模塊
getJSMainModuleName: 配置 js 模塊的入口文件名
2.在 onCreate 中:
調用 Soloader 庫。Soloader 是 facebook 推出的一個 so 文件加載庫,它能夠處理 so 文件的依賴在 react-native 中,所有框架相關的 so 文件都是通過SoLoader完成加載的
通過 ReactInstanceManager 初始化 Flipper。Flipper 是 facebook 推出的用于 debug ios、Android、React Native 應用的工具。
在這里簡要介紹下 ReactNativeHost 和 ReactInstanceManager
ReactNativeHost 是個抽象類,開發者可以重寫其中的方法,其主要的作用是:在 application 中指定一些賦值操作,進而獲取 ReactInstanceManager 的實例。所以可以把 ReactNativeHost 作為將用戶自定義的參數賦值到 ReactInstanceManager 實例的中轉站。核心方法是: getReactInstanceManager,詳細分析見下文。
ReactInstanceManager
該類為核心類,主要負責管理 JS 的加載、維護生命周期、管理 JS 與 C++ 的交互等等??梢园?ReactInstanceManager 理解成 JS 與 C++ 的中轉橋梁。
接著看 MainActivity.java:
public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
return "myProject";
}
}MainActivity 類中僅重寫了 getMainComponentName 方法。該類繼承自 ReactActivity,我們再來看其 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 全權委托給 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);
}
}這里首先創建了 ReactDelegate 實例。接著來看 loadApp 方法:
protected void loadApp(String appKey) {
mReactDelegate.loadApp(appKey);
getPlainActivity().setContentView(mReactDelegate.getReactRootView());
}由此走到 ReactDelegate 實例的 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);
}在這里做了三件事:創建 rootView (createRootView)、創建 ReactInstanceManager (getReactInstanceManager)、創建 ReactApplication (startReactApplication)。
首先看下什么是 rootView。
public class ReactRootView extends FrameLayout implements RootView, ReactRoot { /* ... */}ReactRootView 繼承自 FrameLayout,并且實現了 RootView、ReactRoot 兩個接口。FrameLayout 是安卓幾大布局中較為簡單的一個,整個界面被當成一塊空白備用區域,所有元素以左上角對齊堆疊。ReactRootView 繼承自 FrameLayout,表明其也是作為簡單布局而存在,UI 的繪制渲染都發生在上面。
ReactInstanceManager 是一個核心類,管理著 JS 的加載、C++ 和 JS 的交互、初始化參數等。最終調用來到 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;
}此處做的事情如下:
創建 ReactInstanceManagerBuilder 實例。這里采用建造者模式來構造 ReactInstanceManager 實例,故在此先傳入參數設定構造者;
把在 ReactNativeHost 中注冊的 packages 都添加到 ReactInstanceManagerBuilder 實例中;
如果 getJSBundleFile 不為空,則加載對應的文件,否則加載默認的 jsBundleFile;
調用 builder.build 方法。通過建造者真正構造 ReactInstanceManager 實例
public void startReactApplication(/* */) {
// ...
try {
// ...
mReactInstanceManager.createReactContextInBackground();
} finally {
// ...
}
}最終執行到 ReactInstanceManager 的 createReactContextInBackground 方法中。最后經過調用鏈:recreateReactContextInBackgroundInner() -> recreateReactContextInBackgroundFromBundleLoader() -> recreateReactContextInBackground() -> runCreateReactContextOnNewThread()
runCreateReactContextOnNewThread 主要做了兩件事:
創建一個新的線程,并在新線程中通過 createReactContext 創建 ReactContext 上下文;
通過 setupReactContext 來設置上下文環境,并最終調用到 AppRegistry.js 啟動App。
詳細分析我們放到另一篇文章:React Native startReactApplication 流程梳理。
總結本文,通過 react-native-cli 創建的示例工程(安卓部分)為例,順著兩個類 MainApplication 和 MainActivity 的執行流程,抓住主干邏輯,最終梳理出了 React Native 從開始啟動至執行用戶 js 文件的過程??梢钥吹剑?/p>
MainApplication 的作用主要是傳入用戶的配置,并做 so 庫以及應用 debug 工具的初始化工作;
MainActivity 的作用主要是:
為應用創建 rootView 布局容器;
創建 ReactInstanceManager 核心類,用于后續管理 JS 的加載、C++ 和 JS 的交互、初始化參數等;
通過 startReactApplication 來創建 ReactContext 上下文,并最終調用到 AppRegistry.js 啟動App。
“React Native啟動流程是怎樣的”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。