React Native 启动流程详细解析
导读:本文以 react-native-cli
创建的示例工程(安卓部分)为例,分析 React Native 的启动流程。
工程创建步骤可以参考官网。本文所分析 React Native
版本为 v0.64.2
。
我们知道上述工程是一个安卓应用,打开 android/
目录下源码文件,首先发现它创建了两个 java 文件:MainApplication.java
和 MainActivity.java
,分别做了应用以及主 Activity 的定义。
安卓应用的启动流程是:在启动第一个 activity
之前会创建一个全局唯一的 Application
对象。故在此我们先分析 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(); // 其它对 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
ReactNativeHost
是个抽象类,开发者可以重写其中的方法,其主要的作用是:在 application 中指定一些赋值操作,进而获取 ReactInstanceManager
的实例。所以可以把 ReactNativeHost
作为将用户自定义的参数赋值到 ReactInstanceManager
实例的中转站。核心方法是: getReactInstanceManager
,详细分析见下文。
ReactInstanceManager
该类为核心类,主要负责管理 JS 的加载、维护生命周期、管理 JS 与 C++ 的交互等等。可以把 ReactInstanceManager
理解成 JS 与 C++ 的中转桥梁。
MainActivity
接着看 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
)。
createRootView
首先看下什么是 rootView。
public class ReactRootView extends FrameLayout implements RootView, ReactRoot { /* ... */}
ReactRootView 继承自 FrameLayout
,并且实现了 RootView
、ReactRoot
两个接口。FrameLayout
是安卓几大布局中较为简单的一个,整个界面被当成一块空白备用区域,所有元素以左上角对齐堆叠。ReactRootView 继承自 FrameLayout
,表明其也是作为简单布局而存在,UI 的绘制渲染
都发生在上面。
getReactInstanceManager
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
实例
startReactApplication
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
文件的过程。可以看到:
MainApplication
的作用主要是传入用户的配置,并做 so
库以及应用 debug
工具的初始化工作;
MainActivity
的作用主要是:
- 为应用创建
rootView
布局容器; - 创建
ReactInstanceManager
核心类,用于后续管理 JS 的加载、C++ 和 JS 的交互、初始化参数等; - 通过
startReactApplication
来创建ReactContext
上下文,并最终调用到AppRegistry.js
启动App。
到此这篇关于React Native 启动流程简析的文章就介绍到这了,更多相关React Native 启动内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
相关文章
- 这篇文章主要介绍了Tomcat配置及如何在Eclipse中启动,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-04
关于React Native报Cannot initialize a parameter of type'NSArray<id<RCTBridgeModule>>错误(解决方案)
这篇文章主要介绍了关于React Native报Cannot initialize a parameter of type'NSArray<id<RCTBridgeModule>>错误,本文给大家分享解决方案,需要的朋友可以参考下...2021-05-12php-fpm 启动报please specify user and group other than root, pool ‘default’
本文章来给大家介绍关于php-fpm 启动报please specify user and group other than root, pool ‘default’的解决办法。 安装PHP ,配置fpm 成功后启动发现报错: St...2016-11-25- 这篇文章主要介绍了IDEA 2021.2 启动报错及激活教程,文章开头给大家介绍了idea2021最新激活方法,关于idea2021启动报错的问题小编也给大家介绍的非常详细,需要的朋友可以参考下...2021-10-15
- 在程序执行中会遇到启动本软件的exe问,或者启用其它的exe文件,已达到执行某些操作的作用。下面是两种最常见的启动exe文件。...2020-06-25
- 这篇文章主要介绍了Jrebel启动失败解决方案详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-07-07
- 这篇文章主要介绍了springBoot 项目排除数据库启动方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-10
- centos6.2,停止mysqld然后修改/etc/my.cnf datadir的位置,启动mysqld提示FAILED,查看日志 复制代码 代码如下: 120609 11:31:31 mysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended 120609 11:35:12 my...2015-03-15
React引入antd-mobile+postcss搭建移动端
本文给大家分享React引入antd-mobile+postcss搭建移动端的详细流程,文末给大家分享我的一些经验记录使用antd-mobile时发现我之前配置的postcss失效了,防止大家踩坑,特此把解决方案分享到脚本之家平台,需要的朋友参考下吧...2021-06-21- 这篇文章主要介绍了React使用高德地图的实现示例(react-amap),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-18
使用 React 和 Threejs 创建一个VR全景项目的过程详解
这篇文章主要介绍了使用 React 和 Threejs 创建一个VR全景项目的过程详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-06- 思路其实没有那么复杂,把地图想成一个盒子容器,地图中心点想成盒子中心点;扎点在【地图中心点】不会动,当移动地图时,去获取【地图中心点】经纬度,设置某个位置的时候,将经纬度设置为【地图中心点】即可...2021-06-20
- 这篇文章主要为大家详细介绍了React列表栏及购物车组件使用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-06-28
- 这篇文章主要介绍了react使用antd表单赋值,用于修改弹框的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-29
Apache启动报错No space left on device: AH00023该怎么解决
Apache启动报错No space left on device: AH00023错误可能是进程导致了,虽然小编不知道什么原因但网上提供的解决办法确实是可以解决我们的问题,下面来看看。对于这类错误是因为linux系统的ipc信号量造成的,apache启动时...2015-10-21- 这篇文章主要介绍了React Native 启动流程简析,文以 react-native-cli 创建的示例工程(安卓部分)为例,给大家分析 React Native 的启动流程,需要的朋友可以参考下...2021-08-18
- 这篇文章主要介绍了一百多行代码实现react拖拽hooks,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-21
- useState 通过在函数组件里调用它来给组件添加一些内部 state,React 会在重复渲染时保留这个 state,接下来通过一个示例来看看怎么使用 useState吧...2021-06-04
- 高阶组件就是接受一个组件作为参数并返回一个新组件(功能增强的组件)的函数。这里需要注意高阶组件是一个函数,并不是组件,这一点一定要注意,本文给大家分享React 高阶组件HOC使用小结,一起看看吧...2021-06-13
- 这篇文章主要介绍了@Query注解的原生用法和native用法解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-08-27