React Native for Android 原理分析与实践:实现原理,2024Android开发社招面试解答之性能优化
开发是面向对象。我们找工作应该更多是面向面试。哪怕进大厂真的只是去宁螺丝,但你要进去得先学会面试的时候造飞机不是么?作者13年java转Android开发,在小厂待过,也去过华为,OPPO等,去年四月份进了阿里一直到现在。等大厂待过也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。这里附上上述的技术体系图相关的几十套腾讯、头条
.setUseDeveloperSupport(getUseDeveloperSupport())
//红盒的回调
.setRedBoxHandler(getRedBoxHandler())
//JS执行器
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
//自定义UI实现机制,这个我们一般用不到
.setUIImplementationProvider(getUIImplementationProvider())
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE);
//添加我们外面设置的Package
for (ReactPackage reactPackage : getPackages()) {
builder.addPackage(reactPackage);
}
//获取js Bundle的加载路径
String jsBundleFile = getJSBundleFile();
if (jsBundleFile != null) {
builder.setJSBundleFile(jsBundleFile);
} else {
builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
}
return builder.build();
}
}
2.2 创建ReactContext
我们再来看第二个问题,ReactContext创建流程序列图如下所示:

可以发现,最终创建ReactContext是createReactContext()方法,我们来看看它的实现。
public class ReactInstanceManager {
private ReactApplicationContext createReactContext(
JavaScriptExecutor jsExecutor,
JSBundleLoader jsBundleLoader) {
Log.d(ReactConstants.TAG, “ReactInstanceManager.createReactContext()”);
ReactMarker.logMarker(CREATE_REACT_CONTEXT_START);
//ReactApplicationContext是ReactContext的包装类。
final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext);
//debug模式里开启异常处理器,就是我们开发中见到的调试工具(红色错误框等)
if (mUseDeveloperSupport) {
reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager);
}
//创建JavaModule注册表
NativeModuleRegistry nativeModuleRegistry = processPackages(reactContext, mPackages, false);
NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null
? mNativeModuleCallExceptionHandler
: mDevSupportManager;
//创建CatalystInstanceImpl的Builder,它是三端通信的管理类
CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder()
.setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault())
//JS执行器
.setJSExecutor(jsExecutor)
//Java Module注册表
.setRegistry(nativeModuleRegistry)
//JS Bundle加载器
.setJSBundleLoader(jsBundleLoader)
//Java Exception处理器
.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;
//构建CatalystInstance实例
try {
catalystInstance = catalystInstanceBuilder.build();
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END);
}
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);
//开启加载执行JS Bundle
catalystInstance.runJSBundle();
//关联catalystInstance与reactContext
reactContext.initializeWithInstance(catalystInstance);
return reactContext;
}
}
在这个方法里完成了RN页面上下文ReactContext的创建,我们先来看看这个方法的两个入参:
- JSCJavaScriptExecutor jsExecutor:JSCJavaScriptExecutor继承于JavaScriptExecutor,当该类被加载时,它会自动去加载"reactnativejnifb.so"库,并会调用Native方 法initHybrid()初始化C++层RN与JSC通信的框架。
- JSBundleLoader jsBundleLoader:缓存了JSBundle的信息,封装了上层加载JSBundle的相关接口,CatalystInstance通过其简介调用ReactBridge去加载JS文件,不同的场景会创建 不同的加载器,具体可以查看类JSBundleLoader。
可以看到在ReactContext创建的过程中,主要做了以下几件事情:
- 构建ReactApplicationContext对象,ReactApplicationContext是ReactContext的包装类。
- 利用jsExecutor、nativeModuleRegistry、jsBundleLoader、exceptionHandler等参数构建CatalystInstance实例,作为以为三端通信的中枢。
- 调用CatalystInstance的runJSBundle()开始加载执行JS。
另一个重要的角色CatalystInstance出现了,前面我们也说过它是三端通信的中枢。关于通信的具体实现我们会在接下来的通信机制小节来讲述,我们先来接着看JS的加载过程。
2.3 加载JS Bundle
在分析JS Bundle的加载流程之前,我们先来看一下上面提到CatalystInstance,它是一个接口,其实现类是CatalystInstanceImpl,我们来看看它的构造方法。
public class CatalystInstanceImpl implements CatalystInstance {
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();
//创建三大线程:UI线程、Native线程与JS线程
mReactQueueConfiguration = ReactQueueConfigurationImpl.create(
reactQueueConfigurationSpec,
new NativeExceptionHandler());
mBridgeIdleListeners = new CopyOnWriteArrayList<>();
mNativeModuleRegistry = nativeModuleRegistry;
//创建JS Module注册表实例,这个在以前的代码版本中是在上面的createReactContext()方法中创建的
mJSModuleRegistry = new JavaScriptModuleRegistry();
mJSBundleLoader = jsBundleLoader;
mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler;
mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread();
mTraceListener = new JSProfilerTraceListener(this);
Log.d(ReactConstants.TAG, “Initializing React Xplat Bridge before initializeBridge”);
//在C++层初始化通信桥
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());
}
}
这个函数的入参大部分我们都已经很熟悉了,我们单独说说这个ReactQueueConfigurationSpec,它用来创建ReactQueueConfiguration的实例,ReactQueueConfiguration 同样是个接口,它的实现类是ReactQueueConfigurationImpl。
ReactQueueConfiguration的定义如下:
public interface ReactQueueConfiguration {
//UI线程
MessageQueueThread getUIQueueThread();
//Native线程
MessageQueueThread getNativeModulesQueueThread();
//JS线程
MessageQueueThread getJSQueueThread();
void destroy();
}
可以看着这个接口的作用就是创建三个带消息队列的线程:
- UI线程:Android的UI线程,处理和UI相关的事情。
- Native线程:主要是完成通信的工作。
- JS线程:主要完成JS的执行和渲染工作。
可以看到CatalystInstance对象在构建的时候,主要做了两件事情:
- 创建三大线程:UI线程、Native线程与JS线程。
- 在C++层初始化通信桥。
我们接着来看JS Bundle的加载流程,JS Bundle的加载实际上是指C++层完成的,我们看一下序列图。

注:JS Bundle有三种加载方式:
- setSourceURLs(String deviceURL, String remoteURL) :从远程服务器加载。
- loadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously):从Assets文件夹加载。
- loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously):从文件路径加载。
从这个序列图上我们可以看出,真正加载执行JS的地方就是JSCExector.cpp的loadApplicationScript()方法。
void JSCExecutor::loadApplicationScript(std::unique_ptr script, std::string sourceURL) {
SystraceSection s(“JSCExecutor::loadApplicationScript”,
“sourceURL”, sourceURL);
…
switch (jsStatus) {
case JSLoadSourceIsCompiled:
if (!bcSourceCode) {
throw std::runtime_error(“Unexpected error opening compiled bundle”);
}
//调用JavaScriptCore里的方法验证JS是否有效,并解释执行
evaluateSourceCode(m_context, bcSourceCode, jsSourceURL);
flush();
ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
ReactMarker::logTaggedMarker(ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
return;
case JSLoadSourceErrorVersionMismatch:
throw RecoverableError(explainLoadSourceStatus(jsStatus));
case JSLoadSourceErrorOnRead:
case JSLoadSourceIsNotCompiled:
// Not bytecode, fall through.
break;
}
}
…
可以看到这个方法主要是调用JavaScriptCore里的evaluateSourceCode()方法验证JS是否有效,并解释执行。然后在调用flush()方法层调用JS层的里 方法执行JS Bundle。
void JSCExecutor::flush() {
SystraceSection s(“JSCExecutor::flush”);
if (m_flushedQueueJS) {
//调用MessageQueue.js的flushedQueue()方法
callNativeModules(m_flushedQueueJS->callAsFunction({}));
return;
}
// When a native module is called from JS, BatchedBridge.enqueueNativeCall()
// is invoked. For that to work, require(‘BatchedBridge’) has to be called,
// and when that happens, __fbBatchedBridge is set as a side effect.
auto global = Object::getGlobalObject(m_context);
auto batchedBridgeValue = global.getProperty(“__fbBatchedBridge”);
// So here, if __fbBatchedBridge doesn’t exist, then we know no native calls
// have happened, and we were able to determine this without forcing
// BatchedBridge to be loaded as a side effect.
if (!batchedBridgeValue.isUndefined()) {
// If calls were made, we bind to the JS bridge methods, and use them to
// get the pending queue of native calls.
bindBridge();
callNativeModules(m_flushedQueueJS->callAsFunction({}));
} else if (m_delegate) {
// If we have a delegate, we need to call it; we pass a null list to
// callNativeModules, since we know there are no native calls, without
// calling into JS again. If no calls were made and there’s no delegate,
// nothing happens, which is correct.
callNativeModules(Value::makeNull(m_context));
}
}
上面提到flush()方法调用MessageQueue.js的flushedQueue()方法,这是如何做到的呢?🤔。
事实上这是由bindBridge()方法来完成的,bindBridge()从__fbBatchedBridge(__fbBatchedBridge也是被MessageQueue.js设置为全局变量,供C++层读取)对象中取出MessageQueue.js里的四个方法:
- callFunctionReturnFlushedQueue()
- invokeCallbackAndReturnFlushedQueue()
- flushedQueue()
- callFunctionReturnResultAndFlushedQueue()
并分别存在三个C++变量中:
- m_callFunctionReturnFlushedQueueJS
- m_invokeCallbackAndReturnFlushedQueueJS
- m_flushedQueueJS
- m_callFunctionReturnResultAndFlushedQueueJS
这样C++就可以调用这四个JS方法。
void JSCExecutor::bindBridge() throw(JSException) {
SystraceSection s(“JSCExecutor::bindBridge”);
std::call_once(m_bindFlag, [this] {
auto global = Object::getGlobalObject(m_context);
auto batchedBridgeValue = global.getProperty(“__fbBatchedBridge”);
if (batchedBridgeValue.isUndefined()) {
auto requireBatchedBridge = global.getProperty(“__fbRequireBatchedBridge”);
if (!requireBatchedBridge.isUndefined()) {
batchedBridgeValue = requireBatchedBridge.asObject().callAsFunction({});
}
if (batchedBridgeValue.isUndefined()) {
throw JSException(“Could not get BatchedBridge, make sure your bundle is packaged correctly”);
}
}
auto batchedBridge = batchedBridgeValue.asObject();
m_callFunctionReturnFlushedQueueJS = batchedBridge.getProperty(“callFunctionReturnFlushedQueue”).asObject();
m_invokeCallbackAndReturnFlushedQueueJS = batchedBridge.getProperty(“invokeCallbackAndReturnFlushedQueue”).asObject();
m_flushedQueueJS = batchedBridge.getProperty(“flushedQueue”).asObject();
m_callFunctionReturnResultAndFlushedQueueJS = batchedBridge.getProperty(“callFunctionReturnResultAndFlushedQueue”).asObject();
});
}
至此,JS Bundle已经加载解析完成,进入MessageQueue.js开始执行。
2.4 绑定ReactContext与ReactRootView
JS Bundle加载完成以后,前面说的createReactContext()就执行完成了,然后开始执行setupReacContext()方法,绑定ReactContext与ReactRootView。 我们来看一下它的实现。
public class ReactInstanceManager {
private void setupReactContext(final ReactApplicationContext reactContext) {
//…
//执行Java Module的初始化
catalystInstance.initialize();
//通知ReactContext已经被创建爱女
mDevSupportManager.onNewReactContextCreated(reactContext);
//内存状态回调设置
mMemoryPressureRouter.addMemoryPressureListener(catalystInstance);
//复位生命周期
moveReactContextToCurrentLifecycleState();
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START);
synchronized (mAttachedRootViews) {
//将所有的ReactRootView与catalystInstance进行绑定
for (ReactRootView rootView : mAttachedRootViews) {
attachRootViewToInstance(rootView, catalystInstance);
}
}
//…
}
private void attachRootViewToInstance(
final ReactRootView rootView,
CatalystInstance catalystInstance) {
//…
UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class);
//将ReactRootView作为根布局
final int rootTag = uiManagerModule.addRootView(rootView);
rootView.setRootViewTag(rootTag);
//执行JS的入口bundle页面
rootView.invokeJSEntryPoint();
//…
}
x
}
setupReactContext()方法主要完成每个ReactRootView与catalystInstance的绑定,绑定的过程主要做两件事情:
- 将ReactRootView作为根布局.
- 执行JS的入口bundle页面.
JS的页面入口我们可以设置mJSEntryPoint来自定义入口,如果不设置则是默认的入口AppRegistry。
private void defaultJSEntryPoint() {
//…
try {
//…
String jsAppModuleName = getJSModuleName();
catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams);
} finally {
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
这里的调用方式实际上就是原生调用JS的方法,它调用的正是我们很熟悉的AppRegistry.js,AppRegistry.js调用runApplication()开始执行JS页面的渲染,最终转换为 Native UI显示在手机上。
到此为止,整个RN页面的启动流程就分析完了,我们接着来看看RN页面是如何渲染最终显示在手机上的。
三 渲染原理
上面我们也说了,RN页面的入口一般是AppRegistry.js,我们就从这个页面入手开始分析RN页面的渲染流程。先看一下RN页面的渲染流程序列图,如下所示:

这个流程比较长,其实主要是方法的调用链多,原理还是很简单的,我们先概括性的总结一下:
- React Native将代码由JSX转化为JS组件,启动过程中利用instantiateReactComponent将ReactElement转化为复合组件ReactCompositeComponent与元组件ReactNativeBaseComponent,利用 ReactReconciler对他们进行渲染。
- UIManager.js利用C++层的Instance.cpp将UI信息传递给UIManagerModule.java,并利用UIManagerModule.java构建UI。
- UIManagerModule.java接收到UI信息后,将UI的操作封装成对应的Action,放在队列中等待执行。各种UI的操作,例如创建、销毁、更新等便在队列里完成,UI最终 得以渲染在屏幕上。
3.1 JavaScript层组件渲染

如上图所示AppRegistry.registerComponent用来注册组件,在该方法内它会调用AppRegistry.runApplication()来启动js的渲染流程。AppRegistry.runApplication() 会将传入的Component转换成ReactElement,并在外面包裹一层AppContaniner,AppContaniner主要用来提供一些debug工具(例如:红盒)。
如下所示:
function renderApplication<Props: Object>( RootComponent: ReactClass,
initialProps: Props,
rootTag: any ) {
invariant(
rootTag,
'Expect to have a valid rootTag, instead got ', rootTag
);
ReactNative.render(
<RootComponent
{…initialProps}
rootTag={rootTag}
/>
,
rootTag
);
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。






既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
总结
开发是面向对象。我们找工作应该更多是面向面试。哪怕进大厂真的只是去宁螺丝,但你要进去得先学会面试的时候造飞机不是么?
作者13年java转Android开发,在小厂待过,也去过华为,OPPO等,去年四月份进了阿里一直到现在。等大厂待过也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:


资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
月份进了阿里一直到现在。等大厂待过也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
[外链图片转存中…(img-MlhhSfBK-1711803125373)]
[外链图片转存中…(img-l2tJFIAM-1711803125373)]
资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
更多推荐
所有评论(0)