React Native之Android端Fabric 架构源码分析(上)
前言
Fabric 是 React Native 新架构的 UI 渲染系统,现在我们就来深入分析其源码。
本文基于React Native 0.83版本源码进行分析。
初始化
在《React Native新架构之Android端初始化源码分析》一文已经提过Fabric的初始化部分,现在回顾一下:
// ReactInstance.kt
val eventBeatManager = EventBeatManager()
fabricUIManager =
FabricUIManager(context, ViewManagerRegistry(viewManagerResolver), eventBeatManager)
// 在 Fabric 初始化之前需要完成的其他初始化操作。
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(context)
val binding = FabricUIManagerBinding()
binding.register(
getBufferedRuntimeExecutor(),
getRuntimeScheduler(),
fabricUIManager,
eventBeatManager,
componentFactory,
)
// 初始化 FabricUIManager
fabricUIManager.initialize()
这里EventBeatManager 是 一个基于观察者模式的 Fabric 架构的 "节拍控制器",它利用 Android 原生的帧回调机制,协调并驱动 C++ 层的事件向 JS 层高效、有序地流动。
现在重点看一FabricUIManager的构造方法做了什么react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java:
public FabricUIManager(
ReactApplicationContext reactContext,
ViewManagerRegistry viewManagerRegistry,
BatchEventDispatchedListener batchEventDispatchedListener) {
// 初始化帧回调
mDispatchUIFrameCallback = new DispatchUIFrameCallback(reactContext);
mReactApplicationContext = reactContext;
// 初始化挂载管理器
mMountingManager = new MountingManager(viewManagerRegistry, mMountItemExecutor);
// 初始化挂载指令调度器
mMountItemDispatcher =
new MountItemDispatcher(mMountingManager, new MountItemDispatchListener());
// 初始化事件分发器
mEventDispatcher = new FabricEventDispatcher(reactContext, new FabricEventEmitter(this));
// 持有批处理事件监听器
mBatchEventDispatchedListener = batchEventDispatchedListener;
// 注册生命周期监听
mReactApplicationContext.addLifecycleEventListener(this);
// 注册组件回调
mViewManagerRegistry = viewManagerRegistry;
mReactApplicationContext.registerComponentCallbacks(viewManagerRegistry);
}
这段代码,首先创建一个派生自 Choreographer.FrameCallback的回调,这是 Fabric 渲染的“心脏”。它会注册到 Android 的 Choreographer,在每一帧垂直同步(VSync)信号到来时被调用。它负责驱动 MountItemDispatcher 来执行挂载操作(即实际的 View 更新)。
随后创建了一个挂载管理器MountingManager,它是实际操作 Android View 的管理者(执行 createView, updateProps 等)。接着创建了挂载指令调度器MountItemDispatcher,它负责管理挂载指令(MountItem)的队列,决定它们是在当前线程同步执行还是推入队列等待下一帧执行。当一批指令分发完成后,它会收到回调。这主要用于通知监听器,告诉它们“UI 已经更新了,你们可以进行下一帧动画计算了”。
接下来又创建了事件分发器FabricEventDispatcher,它负责将 Android 原生事件(如 Touch, Scroll)发送给 JavaScript。它的参数FabricEventEmitter是一个实现了 RCTEventEmitter 接口的类,它内部持有 C++ 层的引用(通过 JNI),是 Java 事件通往 C++ Fabric 核心的入口。
以上这写类基本上构成了一套UI系统的核心处理。如果大家需要更深入分析React Native UI系统,那么这些类就是研究的重点。在构造方法的最后,注册了生命周期监听,这是为了让 FabricUIManager 能够感知 Activity/Host 的 onResume, onPause, onDestroy。尤其是在 onHostResume 时恢复 UI 挂载循环,在 onHostPause 时暂停,以节省资源并避免在后台更新 UI。
最后注册组件回调,主要是用于当系统内存不足时,ViewManagerRegistry 可以收到通知并释放缓存。
现在继续分析初始化流程FabricUIManagerBinding的创建,源码react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerBinding.kt:
@DoNotStrip
@SuppressLint("MissingNativeLoadLibrary")
internal class FabricUIManagerBinding : HybridClassBase() {
init {
initHybrid()
}
private external fun initHybrid()
external fun setPixelDensity(pointScaleFactor: Float)
private external fun installFabricUIManager(
runtimeExecutor: RuntimeExecutor,
runtimeScheduler: RuntimeScheduler,
uiManager: FabricUIManager,
eventBeatManager: EventBeatManager,
componentsRegistry: ComponentFactory,
)
fun register(
runtimeExecutor: RuntimeExecutor,
runtimeScheduler: RuntimeScheduler,
fabricUIManager: FabricUIManager,
eventBeatManager: EventBeatManager,
componentFactory: ComponentFactory,
) {
fabricUIManager.setBinding(this)
installFabricUIManager(
runtimeExecutor,
runtimeScheduler,
fabricUIManager,
eventBeatManager,
componentFactory,
)
setPixelDensity(getDisplayMetricDensity())
}
// 省略部分代码......
}
该对象的构造,主要是调用initHybrid方法。关于initHybrid的机制,我们在前面的文章已经做了详细分析,这里就不再重复解释。
这里的FabricUIManagerBinding是 React Native Fabric 架构在 Android 端的 "核心启动器" 和 "跨语言胶水层"。它的主要作用是初始化 Fabric 的 C++ 核心组件,并建立 Java、C++ 和 JavaScript 三者之间的通信桥梁。当该对象被创建时,立即调用了其register方法。在这个方法中,主要是调用了installFabricUIManager,它将 C++ 层的 Fabric API 绑定到 JavaScript 运行时(Runtime)。这使得 JavaScript 可以直接通过 JSI 调用 C++ 接口(如 createNode, cloneNode, appendChild),实现同步且高效的 UI 操作。这里还有一个重要的操作,即setPixelDensity,将 Android 设备的屏幕像素密度(Density)传递给 React Native 的 C++ 核心层(Fabric/Yoga),用于统一布局单位。
最后,分析一下FabricUIManager的initialize做了什么事:
public void initialize() {
// 注册事件批处理监听
mEventDispatcher.addBatchEventDispatchedListener(mBatchEventDispatchedListener);
// 启用 Fabric 日志与性能监控
if (ReactNativeFeatureFlags.enableFabricLogs()) {
mDevToolsReactPerfLogger = new DevToolsReactPerfLogger();
mDevToolsReactPerfLogger.addDevToolsReactPerfLoggerListener(FABRIC_PERF_LOGGER);
ReactMarker.addFabricListener(mDevToolsReactPerfLogger);
}
// 启用新旧架构互操作
if (ReactNativeNewArchitectureFeatureFlags.useFabricInterop()) {
InteropEventEmitter interopEventEmitter = new InteropEventEmitter(mReactApplicationContext);
mReactApplicationContext.internal_registerInteropModule(
RCTEventEmitter.class, interopEventEmitter);
}
}
这里首先是将 mBatchEventDispatchedListener(即 EventBeatManager)注册到事件分发器中。这是 “心跳” 连接的关键一步。当 Android 原生事件(如 Touch)被成批分发时,会通知 EventBeatManager,进而触发 C++ 层的 tick(),驱动 Fabric 渲染管线刷新。没有这一步,JavaScript 可能永远收不到事件更新。
接下来是性能监控相关的处理,开启需依赖enableFabricLogs的值,这是排查 Fabric 性能问题(如掉帧、白屏)和调试渲染流程的“开关”。
最后是启用新旧架构互操作的处理,这是 React Native 平滑迁移到新架构的重要兼容层,确保老代码在新架构下也能工作。
C++层
以上FabricUIManagerBinding提供了很多Native方法,我们在此重点分析一下installFabricUIManager。源码react-native/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp:
void FabricUIManagerBinding::installFabricUIManager(
jni::alias_ref<JRuntimeExecutor::javaobject> runtimeExecutorHolder,
jni::alias_ref<JRuntimeScheduler::javaobject> runtimeSchedulerHolder,
jni::alias_ref<JFabricUIManager::javaobject> javaUIManager,
EventBeatManager* eventBeatManager,
ComponentFactory* componentsRegistry) {
TraceSection s("FabricUIManagerBinding::installFabricUIManager");
enableFabricLogs_ = ReactNativeFeatureFlags::enableFabricLogs();
if (enableFabricLogs_) {
LOG(WARNING)
<< "FabricUIManagerBinding::installFabricUIManager() was called (address: "
<< this << ").";
}
std::unique_lock lock(installMutex_);
// 创建 C++ MountingManager (
auto globalJavaUiManager = make_global(javaUIManager);
mountingManager_ =
std::make_shared<FabricMountingManager>(globalJavaUiManager);
std::shared_ptr<const ContextContainer> contextContainer =
std::make_shared<ContextContainer>();
auto runtimeExecutor = runtimeExecutorHolder->cthis()->get();
auto runtimeScheduler = runtimeSchedulerHolder->cthis()->get().lock();
// 如果存在 RuntimeScheduler(通常都存在),则包装 runtimeExecutor。
// 这意味着所有通过此 executor 提交的 JS 任务都会经过 RuntimeScheduler 调度,从而支持优先级和任务取消。
if (runtimeScheduler) {
runtimeExecutor =
[runtimeScheduler](
std::function<void(jsi::Runtime & runtime)>&& callback) {
runtimeScheduler->scheduleWork(std::move(callback));
};
contextContainer->insert(
RuntimeSchedulerKey, std::weak_ptr<RuntimeScheduler>(runtimeScheduler));
}
// 创建 EventBeat 工厂
EventBeat::Factory eventBeatFactory =
[eventBeatManager, &runtimeScheduler, globalJavaUiManager](
std::shared_ptr<EventBeat::OwnerBox> ownerBox)
-> std::unique_ptr<EventBeat> {
return std::make_unique<AndroidEventBeat>(
std::move(ownerBox),
eventBeatManager,
*runtimeScheduler,
globalJavaUiManager);
};
contextContainer->insert("FabricUIManager", globalJavaUiManager);
// 组装 Scheduler 工具箱
auto toolbox = SchedulerToolbox{};
toolbox.contextContainer = contextContainer;
toolbox.componentRegistryFactory = componentsRegistry->buildRegistryFunction;
// TODO: (T132338609) runtimeExecutor 应该在主 bundle eval 之后执行 lambda 表达式,
// 而 bindingsInstallExecutor 应该在之前执行。
toolbox.bridgelessBindingsExecutor = std::nullopt;
toolbox.runtimeExecutor = runtimeExecutor;
toolbox.eventBeatFactory = eventBeatFactory;
// 启动 Fabric 核心
animationDriver_ = std::make_shared<LayoutAnimationDriver>(
runtimeExecutor, contextContainer, this);
scheduler_ =
std::make_shared<Scheduler>(toolbox, animationDriver_.get(), this);
}
这个方法是一个 "组装车间":
-
它接收来自 Android (Java) 的原材料(
UIManager,EventBeatManager)。 -
它接收来自 JS Runtime 的驱动器(
RuntimeExecutor)。 -
它将这些零件组装成 C++ 的核心部件(
MountingManager,AndroidEventBeat)。 -
最后,它启动了 Fabric 的引擎 ——
Scheduler。
总结
下面是对整个初始化流程的概述
ReactInstance 初始化
│
│
└─► Fabric 初始化
│
├─► ViewManagerResolver 创建 (收集 ReactPackage 中的 ViewManager)
│
├─► ViewManagerRegistry 创建
│
├─► FabricUIManager 创建
│
├─► FabricUIManagerBinding 创建
│
└─► binding.register() ──► 触发 C++ 层初始化
启动渲染
回顾一下Android 的初始化流程一文:
// ReactInstance.kt
/**
* 渲染一个 React Native surface.
*
* @param surface 要渲染的 [com.facebook.react.interfaces.fabric.ReactSurface] 对象
*/
@ThreadConfined("ReactHost")
fun startSurface(surface: ReactSurfaceImpl) {
// 省略部分代码......
val view = surface.view
if (surface.isRunning) {
// Surface 已经在运行(预渲染过),只需附加 View
fabricUIManager.attachRootView(surface.surfaceHandler, view)
} else {
fabricUIManager.startSurface(surface.surfaceHandler, surface.context, view)
}
}
之前并未深入fabricUIManager.startSurface方法的调用,现在来分析一下:
// FabricUIManager.java
public void startSurface(
final SurfaceHandlerBinding surfaceHandler,
final Context context,
final @Nullable View rootView) {
final int rootTag =
rootView instanceof ReactRoot
? ((ReactRoot) rootView).getRootViewTag()
: ReactRootViewTagGenerator.getNextRootViewTag();
ThemedReactContext reactContext =
new ThemedReactContext(
mReactApplicationContext, context, surfaceHandler.getModuleName(), rootTag);
mMountingManager.startSurface(rootTag, reactContext, rootView);
Assertions.assertNotNull(mBinding, "Binding in FabricUIManager is null");
mBinding.startSurfaceWithSurfaceHandler(rootTag, surfaceHandler, rootView != null);
}
此方法主要做了两件事,首先是调用MountingManager的startSurface启动 Surface,接着调用了FabricUIManagerBinding的Native方法startSurfaceWithSurfaceHandler在C++层启动 Surface。先查看react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.kt:
/**
* 启动 Surface 但不附加视图。对该 Surface 执行的所有视图操作都将被排队,直到视图被附加为止。
*/
@AnyThread
fun startSurface(
surfaceId: Int,
reactContext: ThemedReactContext?,
rootView: View?,
): SurfaceMountingManager {
// 创建一个新的 SurfaceMountingManager 实例,负责管理特定 Surface 的视图挂载操作
val surfaceMountingManager =
SurfaceMountingManager(
surfaceId,
jsResponderHandler, // JS 响应处理器(处理触摸事件响应)
viewManagerRegistry,
rootViewManager,
mountItemExecutor, // 挂载项执行器
checkNotNull(reactContext),
)
// 理论上这里可能存在竞态条件,如果 addRootView 从不同线程被调用两次,
// 虽然这种情况(可能)极不可能发生,而且很可能是一个错误。
// 这个防止竞态条件的逻辑是从旧代码继承而来的,我们不知道在实际中是否真的会发生
// 所以,我们现在记录软异常。这在调试模式下会崩溃,但在生产环境中不会。
surfaceIdToManager.putIfAbsent(surfaceId, surfaceMountingManager)
if (surfaceIdToManager[surfaceId] !== surfaceMountingManager) {
logSoftException(
TAG,
IllegalStateException(
"Called startSurface more than once for the SurfaceId [$surfaceId]"
),
)
}
mostRecentSurfaceMountingManager = surfaceIdToManager[surfaceId]
if (rootView != null) {
surfaceMountingManager.attachRootView(rootView, reactContext)
}
return surfaceMountingManager
}
此方法主要内容是创建SurfaceMountingManager,然后调用attachRootView方法。现在继续跟踪attachRootView方法,源码react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java:
public void attachRootView(View rootView, ThemedReactContext themedReactContext) {
mThemedReactContext = themedReactContext;
addRootView(rootView);
}
private void addRootView(@NonNull final View rootView) {
if (isStopped()) {
return; // 检查 Surface 是否已停止
}
mTagToViewState.put(mSurfaceId, new ViewState(mSurfaceId, rootView, mRootViewManager, true));
// 在 UI 线程上执行根视图设置
Runnable runnable =
new GuardedRunnable(Assertions.assertNotNull(mThemedReactContext)) {
@Override
public void runGuarded() {
// 自从调用`addRootView`以来,CPU 一直在运行,因此从理论上讲,界面可能已经在此处停止渲染了。
if (isStopped()) {
return;
}
// 省略部分日志打印......
// 设置根视图 ID
rootView.setId(mSurfaceId);
if (rootView instanceof ReactRoot) {
((ReactRoot) rootView).setRootViewTag(mSurfaceId);
}
executeMountItemsOnViewAttach();
// 通过在调用 `executeMountItemsOnViewAttach` 之后执行此操作,
// 我们可以确保在处理此队列时安排的任何操作也会被添加到队列中,
// 而不是通过 `MountItemDispatcher` 中的队列立即进行处理。
mRootViewAttached = true;
}
};
// 确保在 UI 线程执行
if (UiThreadUtil.isOnUiThread()) {
runnable.run();
} else {
UiThreadUtil.runOnUiThread(runnable);
}
}
这里的实现核心是封装了一个Runnable,即一个任务,且这个任务必须在安卓的UI线程执行。继续跟踪executeMountItemsOnViewAttach方法,查看任务的内容:
private final Queue<MountItem> mOnViewAttachMountItems = new ArrayDeque<>();
@UiThread
@ThreadConfined(UI)
private void executeMountItemsOnViewAttach() {
mMountItemExecutor.executeItems(mOnViewAttachMountItems);
}
可以看到,该方法就是在调用挂载项执行器不断的执行挂载项队列。这里的挂载项执行器是在创建MountingManager时传入的,回到FabricUIManager源码查看实现:
private final MountingManager.MountItemExecutor mMountItemExecutor =
new MountingManager.MountItemExecutor() {
@Override
public void executeItems(Queue<MountItem> items) {
// 从技术上讲,在调度程序创建之前就可以访问这个执行器,但如果真的发生这种情况,那就说明出了非常严重的问题。
mMountItemDispatcher.dispatchMountItems(items);
}
};
继续跟踪react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountItemDispatcher.kt中的实现:
@UiThread
@ThreadConfined(UI)
fun dispatchMountItems(mountItems: Queue<MountItem?>) {
while (!mountItems.isEmpty()) {
val item = requireNotNull(mountItems.poll()) { "MountItem should not be null" }
try {
item.execute(mountingManager)
} catch (e: RetryableMountingLayerException) {
// 省略已弃用的逻辑......
}
}
}
此处核心逻辑是从队列取出一个 MountItem并执行它的execute方法。至于MountItem接口,它有许多实现类,其中最核心的是IntBufferBatchMountItem实现,我们可以大致浏览一下它的execute方法主要做些什么。源码react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.kt:
override fun execute(mountingManager: MountingManager) {
val surfaceMountingManager = mountingManager.getSurfaceManager(surfaceId)
if (surfaceMountingManager == null) {
return
}
if (surfaceMountingManager.isStopped) {
return
}
if (ReactNativeFeatureFlags.enableFabricLogs()) {
FLog.d(TAG, "Executing IntBufferBatchMountItem on surface [%d]", surfaceId)
}
beginMarkers("mountViews")
var i = 0
var j = 0
while (i < intBufferLen) {
val rawType = intBuffer[i++]
val type = rawType and INSTRUCTION_FLAG_MULTIPLE.inv()
val numInstructions =
(if ((rawType and INSTRUCTION_FLAG_MULTIPLE) != 0) intBuffer[i++] else 1)
val args = arrayOf("numInstructions", numInstructions.toString())
for (k in 0 until numInstructions) {
when (type) {
INSTRUCTION_CREATE -> {
val componentName = (objBuffer[j++] as String?).orEmpty()
val fabricComponentName =
FabricNameComponentMapping.getFabricComponentName(componentName)
// 创建视图
surfaceMountingManager.createView(
fabricComponentName,
intBuffer[i++],
objBuffer[j++] as ReadableMap?,
objBuffer[j++] as StateWrapper?,
objBuffer[j++] as EventEmitterWrapper?,
intBuffer[i++] == 1,
)
}
// 删除视图
INSTRUCTION_DELETE -> surfaceMountingManager.deleteView(intBuffer[i++])
INSTRUCTION_INSERT -> {
val tag = intBuffer[i++]
val parentTag = intBuffer[i++]
// 插入视图到父视图
surfaceMountingManager.addViewAt(parentTag, tag, intBuffer[i++])
}
// 从父视图移除
INSTRUCTION_REMOVE ->
surfaceMountingManager.removeViewAt(intBuffer[i++], intBuffer[i++], intBuffer[i++])
// 更新属性
INSTRUCTION_UPDATE_PROPS ->
surfaceMountingManager.updateProps(intBuffer[i++], objBuffer[j++] as ReadableMap?)
// 更新状态
INSTRUCTION_UPDATE_STATE ->
surfaceMountingManager.updateState(intBuffer[i++], objBuffer[j++] as StateWrapper?)
// 更新布局
INSTRUCTION_UPDATE_LAYOUT -> {
val reactTag = intBuffer[i++]
val parentTag = intBuffer[i++]
val x = intBuffer[i++]
val y = intBuffer[i++]
val width = intBuffer[i++]
val height = intBuffer[i++]
val displayType = intBuffer[i++]
val layoutDirection = intBuffer[i++]
surfaceMountingManager.updateLayout(
reactTag,
parentTag,
x,
y,
width,
height,
displayType,
layoutDirection,
)
}
// 省略部分代码......
else -> {
throw IllegalArgumentException(
"Invalid type argument to IntBufferBatchMountItem: $type at index: $i"
)
}
}
}
}
endMarkers()
}
可以看到,IntBufferBatchMountItem包含批量视图操作指令,它使用 int 数组和 object 数组优化性能,减少 JNI 调用,并且支持多种视图操作:创建、删除、插入、移除、更新属性/状态/布局等。
接下来我们跟踪一下surfaceMountingManager.createView的实现,源码react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java:
@UiThread
public void createView(
@NonNull String componentName,
int reactTag,
@Nullable ReadableMap props,
@Nullable StateWrapper stateWrapper,
@Nullable EventEmitterWrapper eventEmitterWrapper,
boolean isLayoutable) {
if (isStopped()) {
return;
}
ViewState viewState = getNullableViewState(reactTag);
if (viewState != null && viewState.mView != null) {
return;
}
createViewUnsafe(
componentName, reactTag, props, stateWrapper, eventEmitterWrapper, isLayoutable);
}
/**
* 执行视图创建操作,但不进行任何安全检查。您必须在调用此方法之前确保安全性(参见现有调用位置)
*/
@UiThread
public void createViewUnsafe(
@NonNull String componentName,
int reactTag,
@Nullable ReadableMap props,
@Nullable StateWrapper stateWrapper,
@Nullable EventEmitterWrapper eventEmitterWrapper,
boolean isLayoutable) {
Systrace.beginSection(
Systrace.TRACE_TAG_REACT,
"SurfaceMountingManager::createViewUnsafe(" + componentName + ")");
try {
ReactStylesDiffMap propMap = new ReactStylesDiffMap(props);
ViewState viewState = new ViewState(reactTag);
viewState.mCurrentProps = propMap;
viewState.mStateWrapper = stateWrapper;
viewState.mEventEmitter = eventEmitterWrapper;
mTagToViewState.put(reactTag, viewState);
if (isLayoutable) {
ViewManager viewManager = mViewManagerRegistry.get(componentName);
// View Managers are responsible for dealing with inital state and props.
viewState.mView =
viewManager.createView(
reactTag, mThemedReactContext, propMap, stateWrapper, mJSResponderHandler);
viewState.mViewManager = viewManager;
}
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT);
}
}
这里是根据组件名通过mViewManagerRegistry来查找ViewManager。具体注册逻辑,我们在后面的注册组件一节分析。
继续跟踪一下viewManager.createView方法的实现,源码react-native/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java:
/** 创建一个了解 props 和 state 的视图。 */
public @NonNull T createView(
int reactTag,
@NonNull ThemedReactContext reactContext,
@Nullable ReactStylesDiffMap props,
@Nullable StateWrapper stateWrapper,
JSResponderHandler jsResponderHandler) {
T view = createViewInstance(reactTag, reactContext, props, stateWrapper);
if (view instanceof ReactInterceptingViewGroup) {
((ReactInterceptingViewGroup) view).setOnInterceptTouchEventListener(jsResponderHandler);
}
return view;
}
/**
* 子类应该返回一个适当类型的新 View 实例。这是一个可选方法,它会为您调用 createViewInstance。
* 如果您需要在创建视图时使用 props 或 state,请重写它。
*
* 如果您重写此方法,您*必须*确保正确处理 updateProperties、view.setId、
* addEventEmitters 和 updateState/updateExtraData!
*
* @param reactTag 应该设置为视图实例 ID 的 reactTag
* @param reactContext 用于初始化视图实例的 ReactContext
* @param initialProps 视图实例的初始 props
* @param stateWrapper 视图实例的初始 state
*/
protected @NonNull T createViewInstance(
int reactTag,
@NonNull ThemedReactContext reactContext,
@Nullable ReactStylesDiffMap initialProps,
@Nullable StateWrapper stateWrapper) {
T view = null;
@Nullable Stack<T> recyclableViews = getRecyclableViewStack(reactContext.getSurfaceId(), true);
if (recyclableViews != null && !recyclableViews.empty()) {
T recyclableView = recyclableViews.pop();
// 当视图回收未对所有组件启用时,可回收视图仍可能附加到不可回收视图。
// 这保证了回收视图已从其父视图中移除。
if (ReactNativeFeatureFlags.enableViewRecycling() && recyclableView.getParent() != null) {
((ViewGroup) recyclableView.getParent()).removeView(recyclableView);
}
view = recycleView(reactContext, recyclableView);
} else {
view = createViewInstance(reactContext);
}
view.setId(reactTag);
addEventEmitters(reactContext, view);
if (initialProps != null) {
updateProperties(view, initialProps);
}
// 仅在 Fabric 架构中存在;但在 Fabric 中始终存在。
if (stateWrapper != null) {
Object extraData = updateState(view, initialProps, stateWrapper);
if (extraData != null) {
updateExtraData(view, extraData);
}
}
return view;
}
/**
* 子类应该返回一个适当类型的新 View 实例。
*/
protected abstract @NonNull T createViewInstance(@NonNull ThemedReactContext reactContext);
/**
* 子类可以重写此方法以在给定 View 上安装自定义事件发射器。
* 如果您的视图需要向 JS 发送除基本触摸事件之外的事件(例如滚动事件),
* 您可能想要重写此方法。
*/
protected void addEventEmitters(@NonNull ThemedReactContext reactContext, @NonNull T view) {}
/**
* 子类可以实现此方法以接收从 {@link ReactShadowNode#onCollectExtraUpdates} 中
* 相应 {@link ReactShadowNode} 实例排队的可选额外数据。
*
* 由于 CSS 布局步骤和 UI 更新可以在设置 x/y/width/height 之外的单独线程中执行,
* 这是从 CSS 节点向原生视图对应部分传递额外数据的推荐且线程安全的方式。
*
* <p>TODO T7247021: Replace updateExtraData with generic update props mechanism after D2086999
*/
public abstract void updateExtraData(@NonNull T view, Object extraData);
/**
* 子类可以实现此方法以接收在此组件类型的所有实例之间共享的状态更新。
*/
public @Nullable Object updateState(
@NonNull T view, ReactStylesDiffMap props, StateWrapper stateWrapper) {
return null;
}
这里比较重要的是createViewInstance方法,子类必须重写它,用于创建自定义View。现在查看一下我们创建的自定义Fabric 组件包中自动生成的模版代码:
@ReactModule(name = CustomWebViewManager.NAME)
class CustomWebViewManager : SimpleViewManager<CustomWebView>(),
CustomWebViewManagerInterface<CustomWebView> {
private val mDelegate: ViewManagerDelegate<CustomWebView>
init {
mDelegate = CustomWebViewManagerDelegate(this)
}
override fun getDelegate(): ViewManagerDelegate<CustomWebView>? {
return mDelegate
}
override fun getName(): String {
return NAME
}
public override fun createViewInstance(context: ThemedReactContext): CustomWebView {
return CustomWebView(context)
}
@ReactProp(name = "sourceURL")
override fun setSourceURL(view: CustomWebView?, sourceURL: String?) {
// Implement the logic to handle the sourceURL property
}
companion object {
const val NAME = "CustomWebView"
}
}
可以看到,CustomWebViewManager实际上就是ViewManager的子孙类,其实现了createViewInstance方法,返回自定义的View实例。
这条线的跟踪已经足够深入了,关于原生UI组件的具体布局渲染就不继续了,先到此为止。
C++ 层
FabricUIManager的startSurface方法中还有一个Native方法mBinding.startSurfaceWithSurfaceHandler未分析,源码react-native/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp:
void FabricUIManagerBinding::startSurfaceWithSurfaceHandler(
jint surfaceId,
jni::alias_ref<SurfaceHandlerBinding::jhybridobject> surfaceHandlerBinding,
jboolean isMountable) {
// SurfaceHandler配置
// 从JNI包装中提取C++ SurfaceHandler对象
const auto& surfaceHandler =
surfaceHandlerBinding->cthis()->getSurfaceHandler();
surfaceHandler.setSurfaceId(surfaceId);
// 根据是否有View设置显示模式
surfaceHandler.setDisplayMode(
isMountable != 0 ? DisplayMode::Visible : DisplayMode::Suspended);
// 获取Fabric调度器
auto scheduler = getScheduler();
if (!scheduler) {
LOG(ERROR)
<< "FabricUIManagerBinding::startSurfaceWithSurfaceHandler: scheduler disappeared";
return;
}
// 将SurfaceHandler注册到调度器中。调度器负责管理渲染和布局
scheduler->registerSurface(surfaceHandler);
auto mountingManager = getMountingManager("startSurfaceWithSurfaceHandler");
if (mountingManager != nullptr) {
// 通知MountingManager, Surface开始启动
// MountingManager负责将C++的UI操作转换为Android原生View操作
mountingManager->onSurfaceStart(surfaceId);
}
// 启动SurfaceHandler
surfaceHandler.start();
// 如果启用布局动画,设置动画驱动器
if (ReactNativeFeatureFlags::enableLayoutAnimationsOnAndroid()) {
surfaceHandler.getMountingCoordinator()->setMountingOverrideDelegate(
animationDriver_);
}
{
std::unique_lock lock(surfaceHandlerRegistryMutex_);
// 将SurfaceHandler添加到注册表中,便于后续管理(停止、更新等)
surfaceHandlerRegistry_.emplace(
surfaceId, jni::make_weak(surfaceHandlerBinding));
}
}
这个方法是新架构Surface启动的关键桥梁,它体现了新架构的核心特点:通过JSI直接从C++调用JS。
-
向上:接收Java层的启动请求
-
向下:触发C++层的Surface启动流程
-
横向:协调Scheduler、MountingManager等各个子系统
这里重点关注一下surfaceHandler.start()的实现,源码react-native/packages/react-native/ReactCommon/react/renderer/scheduler/SurfaceHandler.cpp:
void SurfaceHandler::start() const noexcept {
std::unique_lock lock(linkMutex_);
// 省略断言......
auto parameters = Parameters{};
{
std::shared_lock parametersLock(parametersMutex_);
parameters = parameters_;
}
// 创建ShadowTree
auto shadowTree = std::make_unique<ShadowTree>(
parameters.surfaceId,
parameters.layoutConstraints,
parameters.layoutContext,
*link_.uiManager,
*parameters.contextContainer);
// 将ShadowTree指针保存到link_中,供后续操作使用
link_.shadowTree = shadowTree.get();
if (!parameters.moduleName.empty()) {
// 启动Surface
link_.uiManager->startSurface(
std::move(shadowTree),
parameters.moduleName,
parameters.props,
parameters_.displayMode);
} else {
// 创建空Surface,仅用于预渲染
link_.uiManager->startEmptySurface(std::move(shadowTree));
}
// 将状态从Registered更新为Running
link_.status = Status::Running;
// 应用显示模式
applyDisplayMode(parameters.displayMode);
}
此方法是Fabric架构中渲染流程的起点,负责创建ShadowTree并启动UI渲染流程。这里的ShadowTree就是Fabric中的虚拟DOM树,用于布局计算和渲染。
继续跟踪uiManager->startSurface的实现,源码react-native/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp:
void UIManager::startSurface(
ShadowTree::Unique&& shadowTree,
const std::string& moduleName,
const folly::dynamic& props,
DisplayMode displayMode) const noexcept {
TraceSection s("UIManager::startSurface");
// ShadowTree注册
auto surfaceId = shadowTree->getSurfaceId();
shadowTreeRegistry_.add(std::move(shadowTree));
// 委托通知
// 使用访问者模式安全访问已注册的ShadowTree
shadowTreeRegistry_.visit(
surfaceId, [delegate = delegate_](const ShadowTree& shadowTree) {
if (delegate != nullptr) {
// 通知UIManager的委托对象Surface已启动
delegate->uiManagerDidStartSurface(shadowTree);
}
});
// 异步调用JS层
runtimeExecutor_([=](jsi::Runtime& runtime) {
TraceSection s("UIManager::startSurface::onRuntime");
// 在JS线程上异步执行
AppRegistryBinding::startSurface(
runtime, surfaceId, moduleName, props, displayMode);
});
}
此方法是Fabric架构中连接C++渲染系统和JS应用层的关键桥梁方法,负责注册ShadowTree并触发JS应用启动。
继续跟踪AppRegistryBinding::startSurface。源码react-native/packages/react-native/ReactCommon/react/renderer/uimanager/AppRegistryBinding.cpp:
/* static */ void AppRegistryBinding::startSurface(
jsi::Runtime& runtime,
SurfaceId surfaceId,
const std::string& moduleName,
const folly::dynamic& initialProps,
DisplayMode displayMode) {
TraceSection s("AppRegistryBinding::startSurface");
// 构建参数对象
jsi::Object parameters(runtime);
parameters.setProperty(runtime, "rootTag", surfaceId);
parameters.setProperty(
runtime, "initialProps", jsi::valueFromDynamic(runtime, initialProps));
parameters.setProperty(runtime, "fabric", true);
// 获取全局AppRegistry
// 访问JS全局对象
auto global = runtime.global();
// 查找RN$AppRegistry(在AppRegistry.js中设置)
auto registry = global.getProperty(runtime, "RN$AppRegistry");
if (!registry.isObject()) {
throw std::runtime_error(
"AppRegistryBinding::startSurface failed. Global was not installed.");
}
// 获取runApplication方法对象
auto method = std::move(registry).asObject(runtime).getPropertyAsFunction(
runtime, "runApplication");
// 调用JS方法:runApplication
method.call(
runtime,
{jsi::String::createFromUtf8(runtime, moduleName),
std::move(parameters),
jsi::Value(runtime, displayModeToInt(displayMode))});
}
这里的重点是就是JS层的runApplication方法调用,可以说这就是JS层的入口方法。此处的JSI C++调用等价于以下JS代码:
AppRegistry.runApplication(
"RNTesterApp", // moduleName
{
rootTag: 1, // surfaceId
initialProps: {...}, // 初始属性
fabric: true // 新架构标记
},
0 // displayMode
);
AppRegistryBinding::startSurface方法是新架构调用链的终点,负责通过JSI直接调用JS层的AppRegistry.runApplication,启动React Native应用。
渲染调度
接下来我们探索一下前面提到的mOnViewAttachMountItems队列:
// SurfaceMountingManager.java
@UiThread
@ThreadConfined(UI)
public void scheduleMountItemOnViewAttach(MountItem item) {
mOnViewAttachMountItems.add(item);
}
经过搜索,可以定位到scheduleMountItemOnViewAttach调用处:
// MountItemDispatcher.kt
private fun getAndResetViewCommandMountItems(): List<DispatchCommandMountItem>? =
drainConcurrentItemQueue(viewCommandMountItems)
private fun getAndResetMountItems(): List<MountItem>? = drainConcurrentItemQueue(mountItems)
private fun getAndResetPreMountItems(): List<MountItem>? = drainConcurrentItemQueue(preMountItems)
private fun executeOrEnqueue(item: MountItem) {
if (mountingManager.isWaitingForViewAttach(item.getSurfaceId())) {
// Surface 还未准备好,将任务加入等待队列
val surfaceMountingManager: SurfaceMountingManager =
mountingManager.getSurfaceManagerEnforced(
item.getSurfaceId(),
"MountItemDispatcher::executeOrEnqueue",
)
surfaceMountingManager.scheduleMountItemOnViewAttach(item)
} else {
// Surface 已准备好,直接执行
item.execute(mountingManager)
}
}
/*
* 按以下顺序执行视图命令、预挂载项和挂载项:
* 1. 视图命令
* 2. 预挂载项
* 3. 常规挂载项
*
* 如果 `viewCommandMountItemsToDispatch` 和 `mountItemsToDispatch` 都为空,则不执行任何操作。
* 除了 `tryDispatchMountItems` 之外,任何地方都不应直接调用此方法。
*/
@UiThread
@ThreadConfined(UI)
private fun dispatchMountItems() {
batchedExecutionTime = 0
runStartTime = SystemClock.uptimeMillis()
// 初始化和获取待分发项
val viewCommandMountItemsToDispatch = getAndResetViewCommandMountItems()
val mountItemsToDispatch = getAndResetMountItems()
if (mountItemsToDispatch == null && viewCommandMountItemsToDispatch == null) {
return
}
itemDispatchListener.willMountItems(mountItemsToDispatch)
// 定义视图命令分发函数
val dispatchViewCommand: (command: DispatchCommandMountItem) -> Unit = { command ->
if (ReactNativeFeatureFlags.enableFabricLogs()) {
printMountItem(command, "dispatchMountItems: Executing viewCommandMountItem")
}
try {
executeOrEnqueue(command)
} catch (e: RetryableMountingLayerException) {
// 省略......
} catch (e: Throwable) {
// 省略......
}
}
// 执行ViewCommand
// 作为优化,首先执行所有 ViewCommand
// 这应该是:
// 1) 高性能的:ViewCommand 通常是 SetNativeProps 的替代品,我们一直希望它尽可能"同步"。
// 2) 更安全的:ViewCommand 本质上与树提交/差异/挂载过程断开连接。
// JS 令式地排队这些命令。
// 如果 JS 已经排队了一个命令,可以合理地假设时间过得越久, 视图消失的可能性就越大。
// 因此,通过提前执行 ViewCommand,我们实际上应该避免一类错误/故障。
viewCommandMountItemsToDispatch?.let { commands ->
for (command in commands) {
dispatchViewCommand(command)
}
Systrace.endSection(Systrace.TRACE_TAG_REACT)
}
// 执行PreMountItem
// 如果有 MountItem 要分发,我们确保所有"预挂载项"首先执行
getAndResetPreMountItems()?.let { preMountItems ->
for (preMountItem in preMountItems) {
if (ReactNativeFeatureFlags.enableFabricLogs()) {
printMountItem(preMountItem, "dispatchMountItems: Executing preMountItem")
}
executeOrEnqueue(preMountItem)
}
Systrace.endSection(Systrace.TRACE_TAG_REACT)
}
// 执行常规 MountItem
mountItemsToDispatch?.let { items ->
val batchedExecutionStartTime = SystemClock.uptimeMillis()
for (mountItem in items) {
if (ReactNativeFeatureFlags.enableFabricLogs()) {
printMountItem(mountItem, "dispatchMountItems: Executing mountItem")
}
val command = mountItem as? DispatchCommandMountItem
if (command != null) {
dispatchViewCommand(command)
continue
}
try {
executeOrEnqueue(mountItem)
} catch (e: Throwable) {
// 省略......
}
}
batchedExecutionTime += SystemClock.uptimeMillis() - batchedExecutionStartTime
}
itemDispatchListener.didMountItems(mountItemsToDispatch)
}
/**
* 尝试分发 MountItems。如果出现异常,我们将重试 10 次后放弃。
*/
fun tryDispatchMountItems() {
// 如果我们已经在分发中,不要重入。在 Android 的 Fabric 中可能经常发生重入,
// 因为来自挂载层的 `updateState` 会导致挂载项被同步分发。我们想要
// 1)确保在这些情况下不重入,但 2)仍然同步执行这些排队的指令。
// 这是一个相当粗暴的工具,但我们可能没有更好的选择,因为我们真的不想执行任何乱序的操作。
if (inDispatch) {
return
}
inDispatch = true
try {
dispatchMountItems()
} finally {
// 即使抛出异常也要在运行 dispatchMountItems 后清理
inDispatch = false
}
// 无论我们是否实际分发了任何内容,我们都会调用 didDispatchMountItems,
// 因为 NativeAnimatedModule 依赖于此来执行可能已调度的任何动画
itemDispatchListener.didDispatchMountItems()
}
可以看到,scheduleMountItemOnViewAttach仅被executeOrEnqueue方法调用。只有在Surface 还未准备好时,才将任务加入等待队列。否则,直接在executeOrEnqueue中执行挂载项。
这里executeOrEnqueue方法在dispatchMountItems方法中有三次调用,分别对应着三个队列。这三个队列存在执行顺序:
-
ViewCommand 优先执行:提高性能和安全性(存储视图命令,如 scrollTo、focus等,这些是来自 JS 的命令式调用,与视图树的提交/差异/挂载过程分离)
-
PreMountItem 次之:为后续挂载做准备(存储预挂载项,主要是视图预分配操作。这是性能优化,尽可能提前完成工作)
-
常规 MountItem 最后:执行实际的视图操作(存储常规挂载项,包含主要的视图操作。这是视图树更新的核心操作)
有个地方需要注意,就是drainConcurrentItemQueue方法。此方法是一次性清空队列,将结果转为一个List。之所以这样做,是为了将累积的所有挂载项一次性取出进行批处理,避免在执行过程中队列继续增长导致的不一致性。这里的三个队列都调用了此方法返回列表。
接下来,根据注释可知,dispatchMountItems方法只应该被tryDispatchMountItems调用。而tryDispatchMountItems方法主要做了一个防止重入的处理。继续搜索该方法,发现只有两处调用,且都在FabricUIManager.java中:
private class DispatchUIFrameCallback extends GuardedFrameCallback {
private volatile boolean mIsMountingEnabled = true;
@ThreadConfined(UI)
private boolean mShouldSchedule = false;
@ThreadConfined(UI)
private boolean mIsScheduled = false;
private DispatchUIFrameCallback(ReactContext reactContext) {
super(reactContext);
}
@UiThread
@ThreadConfined(UI)
private void schedule() {
if (!mIsScheduled && mShouldSchedule) {
mIsScheduled = true;
ReactChoreographer.getInstance()
.postFrameCallback(ReactChoreographer.CallbackType.DISPATCH_UI, this);
}
}
// 省略部分代码......
@Override
@UiThread
@ThreadConfined(UI)
public void doFrameGuarded(long frameTimeNanos) {
mIsScheduled = false;
if (!mIsMountingEnabled) {
return;
}
if (mDestroyed) {
return;
}
// 通过 C++ 驱动所有动画。
// 这里存在获取/设置 `mDriveCxxAnimations` 的竞态条件,但这应该无关紧要;
// 调用 mBinding 方法是安全的,除非 mBinding 对象已被销毁。
if ((mDriveCxxAnimations || ReactNativeFeatureFlags.cxxNativeAnimatedEnabled())
&& mBinding != null) {
mBinding.driveCxxAnimations();
}
if (mBinding != null) {
mBinding.drainPreallocateViewsQueue();
}
try {
// 首先,在 frameTimeNanos 时间内执行尽可能多的预挂载项。
// 如果不是所有预挂载项都被执行,可能发生以下情况:
// 1. 如果 MountItemDispatcher 中有视图命令或挂载项:执行剩余的预挂载项。
// 2. 如果没有视图命令或挂载项,等待下一帧。
mMountItemDispatcher.dispatchPreMountItems(frameTimeNanos);
mMountItemDispatcher.tryDispatchMountItems();
} catch (Exception ex) {
FLog.e(TAG, "Exception thrown when executing UIFrameGuarded", ex);
mIsMountingEnabled = false;
throw ex;
} finally {
schedule();
}
mSynchronousEvents.clear();
}
}
先看doFrameGuarded这处调用,这里正是一开始分析初始化流程时提到的基于 Android Choreographer帧回调处理。
-
监听 VSync 信号
-
在每帧开始时触发回调
-
按优先级顺序执行回调队列
-
mBinding.driveCxxAnimations()- C++ 动画 -
mBinding.drainPreallocateViewsQueue()- C++ 预分配队列 -
dispatchPreMountItems(frameTimeNanos)- Java 预挂载项 -
tryDispatchMountItems()- 常规挂载项
-
doFrameGuarded这处调用就是正常的帧驱动渲染流程,确保 UI 更新与屏幕刷新同步。
我们再看另一处调用:
/**
* 此方法将 UI 操作直接添加到 UI 线程队列中。以使用 {@link ReactChoreographer.CallbackType} 来强制执行顺序。
* 此方法应仅在提交新渲染树后调用。
*/
@SuppressWarnings("unused")
@AnyThread
@ThreadConfined(ANY)
private void scheduleMountItem(
@Nullable final MountItem mountItem,
int commitNumber,
long commitStartTime,
long diffStartTime,
long diffEndTime,
long layoutStartTime,
long layoutEndTime,
long finishTransactionStartTime,
long finishTransactionEndTime,
int affectedLayoutNodesCount) {
// 当 Binding.cpp 在提交阶段调用 scheduleMountItems 时,它总是使用 BatchMountItem 调用。
// 没有其他地方使用 BatchMountItem 调用此方法,并且 Binding.cpp 只使用 BatchMountItem 调用 scheduleMountItems。
long scheduleMountItemStartTime = SystemClock.uptimeMillis();
boolean isBatchMountItem = mountItem instanceof BatchMountItem;
boolean shouldSchedule = false;
// 判断是否为批量挂载项
if (isBatchMountItem) {
BatchMountItem batchMountItem = (BatchMountItem) mountItem;
Assertions.assertNotNull(batchMountItem, "BatchMountItem is null");
shouldSchedule = !batchMountItem.isBatchEmpty();
} else {
shouldSchedule = mountItem != null;
}
// 省略性能记录......
// 通知监听器
// 在同步渲染的情况下,这可能在 UI 线程上被调用。否则,
// 它应该几乎总是在 JS 线程上被调用。
for (UIManagerListener listener : mListeners) {
listener.didScheduleMountItems(this);
}
// 调度执行
if (shouldSchedule) {
Assertions.assertNotNull(mountItem, "MountItem is null");
// 将 MountItem 添加到分发器队列
mMountItemDispatcher.addMountItem(mountItem);
// 判断是否是UI线程,如果是UI线程则立即执行,实现低延迟渲染
if (UiThreadUtil.isOnUiThread()) {
Runnable runnable =
new GuardedRunnable(mReactApplicationContext) {
@Override
public void runGuarded() {
mMountItemDispatcher.tryDispatchMountItems();
}
};
runnable.run();
}
}
// 在锁外和同步挂载完成执行后发布标记
if (isBatchMountItem) {
// 省略部分代码......
}
}
可以看到,此方法是由C++层调用,在其中实现了双路径执行渲染策略。当前如果在UI线程调用,则会立即执行渲染。反之,只是通过mMountItemDispatcher.addMountItem(mountItem)将 MountItem 添加到队列,等待帧回调处理:
// MountItemDispatcher.kt
fun addMountItem(mountItem: MountItem) {
mountItems.add(mountItem)
}
C++ 层
现在来研究一下C++层触发scheduleMountItem的流程,源码react-native/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp:
jsi::Value UIManagerBinding::get(
jsi::Runtime& runtime,
const jsi::PropNameID& name) {
auto methodName = name.utf8(runtime);
UIManager* uiManager = uiManager_.get();
// 省略部分代码......
if (methodName == "completeRoot") {
auto paramCount = 2;
return jsi::Function::createFromHostFunction(
runtime,
name,
paramCount,
[uiManager, methodName, paramCount](
jsi::Runtime& runtime,
const jsi::Value& /*thisValue*/,
const jsi::Value* arguments,
size_t count) -> jsi::Value {
validateArgumentCount(runtime, methodName, paramCount, count);
auto runtimeSchedulerBinding =
RuntimeSchedulerBinding::getBinding(runtime);
auto surfaceId = surfaceIdFromValue(runtime, arguments[0]);
auto shadowNodeList = shadowNodeListFromValue(runtime, arguments[1]);
uiManager->completeSurface(
surfaceId,
shadowNodeList,
{.enableStateReconciliation = true,
.mountSynchronously = false,
.source = ShadowTree::CommitSource::React});
return jsi::Value::undefined();
});
}
// 省略部分代码......
return jsi::Value::undefined();
}
继续跟踪completeSurface方法实现,源码react-native/packages/react-native/ReactCommon/react/renderer/uimanager/UIManager.cpp:
void UIManager::completeSurface(
SurfaceId surfaceId,
const ShadowNode::UnsharedListOfShared& rootChildren,
ShadowTree::CommitOptions commitOptions) {
TraceSection s("UIManager::completeSurface", "surfaceId", surfaceId);
shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree& shadowTree) {
auto result = shadowTree.commit(
[&](const RootShadowNode& oldRootShadowNode) {
return std::make_shared<RootShadowNode>(
oldRootShadowNode,
ShadowNodeFragment{
.props = ShadowNodeFragment::propsPlaceholder(),
.children = rootChildren,
});
},
commitOptions);
if (result == ShadowTree::CommitStatus::Succeeded) {
// It's safe to update the visible revision of the shadow tree immediately
// after we commit a specific one.
lazyShadowTreeRevisionConsistencyManager_->updateCurrentRevision(
surfaceId, shadowTree.getCurrentRevision().rootShadowNode);
}
});
}
这里的核心是ShadowTree::commit方法的调用,实参是个闭包。它主要用于计算 Diff,生成 MountingTransaction。继续跟踪源码react-native/packages/react-native/ReactCommon/react/renderer/mounting/ShadowTree.cpp:
CommitStatus ShadowTree::commit(
const ShadowTreeCommitTransaction& transaction,
const CommitOptions& commitOptions) const {
[[maybe_unused]] int attempts = 0;
if (ReactNativeFeatureFlags::preventShadowTreeCommitExhaustion()) {
while (attempts < MAX_COMMIT_ATTEMPTS_BEFORE_LOCKING) {
auto status = tryCommit(transaction, commitOptions);
if (status != CommitStatus::Failed) {
return status;
}
attempts++;
}
{
std::unique_lock lock(commitMutexRecursive_);
return tryCommit(transaction, commitOptions);
}
} else {
// 循环尝试提交,直到成功或达到最大尝试次数
while (true) {
attempts++;
auto status = tryCommit(transaction, commitOptions);
if (status != CommitStatus::Failed) {
return status;
}
// After multiple attempts, we failed to commit the transaction.
// Something internally went terribly wrong.
react_native_assert(attempts < 1024);
}
}
}
CommitStatus ShadowTree::tryCommit(
const ShadowTreeCommitTransaction& transaction,
const CommitOptions& commitOptions) const {
TraceSection s("ShadowTree::commit");
auto telemetry = TransactionTelemetry{};
telemetry.willCommit();
CommitMode commitMode;
auto oldRevision = ShadowTreeRevision{};
auto newRevision = ShadowTreeRevision{};
{
// Reading `currentRevision_` in shared manner.
SharedLock lock = sharedCommitLock();
commitMode = commitMode_;
oldRevision = currentRevision_;
}
const auto& oldRootShadowNode = oldRevision.rootShadowNode;
// 1. 执行 transaction,生成新的 RootShadowNode
auto newRootShadowNode = transaction(*oldRevision.rootShadowNode);
if (!newRootShadowNode) {
return CommitStatus::Cancelled;
}
// 2. 状态协调(State Reconciliation)
if (commitOptions.enableStateReconciliation) {
auto updatedNewRootShadowNode =
progressState(*newRootShadowNode, *oldRootShadowNode);
if (updatedNewRootShadowNode) {
newRootShadowNode =
std::static_pointer_cast<RootShadowNode>(updatedNewRootShadowNode);
}
}
// 3. 调用 delegate 的 shadowTreeWillCommit hook
newRootShadowNode = delegate_.shadowTreeWillCommit(
*this, oldRootShadowNode, newRootShadowNode, commitOptions);
if (!newRootShadowNode) {
return CommitStatus::Cancelled;
}
// Layout nodes.
std::vector<const LayoutableShadowNode*> affectedLayoutableNodes{};
affectedLayoutableNodes.reserve(1024);
telemetry.willLayout();
telemetry.setAsThreadLocal();
// 4. 布局计算
newRootShadowNode->layoutIfNeeded(&affectedLayoutableNodes);
telemetry.unsetAsThreadLocal();
telemetry.didLayout(static_cast<int>(affectedLayoutableNodes.size()));
{
// Updating `currentRevision_` in unique manner if it hasn't changed.
UniqueLock lock = uniqueCommitLock();
if (currentRevision_.number != oldRevision.number) {
return CommitStatus::Failed;
}
auto newRevisionNumber = currentRevision_.number + 1;
{
std::scoped_lock dispatchLock(EventEmitter::DispatchMutex());
updateMountedFlag(
currentRevision_.rootShadowNode->getChildren(),
newRootShadowNode->getChildren(),
commitOptions.source);
}
telemetry.didCommit();
telemetry.setRevisionNumber(static_cast<int>(newRevisionNumber));
// Seal the shadow node so it can no longer be mutated
// Does nothing in release.
newRootShadowNode->sealRecursive();
newRevision = ShadowTreeRevision{
.rootShadowNode = std::move(newRootShadowNode),
.number = newRevisionNumber,
.telemetry = telemetry};
// 5. 更新 currentRevision_
currentRevision_ = newRevision;
}
// 6. 发送布局事件
emitLayoutEvents(affectedLayoutableNodes);
// 7. 关键:如果 commitMode 是 Normal,调用 mount
if (commitMode == CommitMode::Normal) {
mount(std::move(newRevision), commitOptions.mountSynchronously);
}
return CommitStatus::Succeeded;
}
void ShadowTree::mount(ShadowTreeRevision revision, bool mountSynchronously)
const {
// 1. 将新的 revision 推送到 MountingCoordinator
mountingCoordinator_->push(std::move(revision));
// 2. 调用 delegate 的 shadowTreeDidFinishTransaction
delegate_.shadowTreeDidFinishTransaction(
mountingCoordinator_, mountSynchronously);
}
注意,ShadowTreeRevision 表示 Shadow Tree 的一个已提交快照(版本)。由三个组成部分:
-
rootShadowNode:整个 Shadow Tree 的根节点,包含完整的树结构和所有子节点 -
number:版本号,从 0(INITIAL_REVISION)开始递增,每次 commit 创建新 revision 时递增。主要用于检测并发冲突和版本追踪 -
telemetry:性能数据(commit 时间、layout 时间、影响的节点数等
MountingCoordinator 使用 revision 来计算新旧树之间的差异,生成需要执行的视图操作。
继续跟踪shadowTreeDidFinishTransaction的实现:
// UIManager.cpp
void UIManager::shadowTreeDidFinishTransaction(
std::shared_ptr<const MountingCoordinator> mountingCoordinator,
bool mountSynchronously) const {
TraceSection s("UIManager::shadowTreeDidFinishTransaction");
if (delegate_ != nullptr) {
delegate_->uiManagerDidFinishTransaction(
std::move(mountingCoordinator), mountSynchronously);
}
}
继续跟踪uiManagerDidFinishTransaction实现,源码react-native/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp:
void Scheduler::uiManagerDidFinishTransaction(
std::shared_ptr<const MountingCoordinator> mountingCoordinator,
bool mountSynchronously) {
TraceSection s("Scheduler::uiManagerDidFinishTransaction");
if (delegate_ != nullptr) {
// 除了 Android 平台之外,此操作在所有平台上均无效,
// 因为在 Android 平台上我们需要观察每个事务才能正确地进行挂载。
delegate_->schedulerDidFinishTransaction(mountingCoordinator);
if (!mountSynchronously) {
auto surfaceId = mountingCoordinator->getSurfaceId();
runtimeScheduler_->scheduleRenderingUpdate(
surfaceId,
[delegate = delegate_,
mountingCoordinator = std::move(mountingCoordinator)]() {
delegate->schedulerShouldRenderTransactions(mountingCoordinator);
});
} else {
delegate_->schedulerShouldRenderTransactions(mountingCoordinator);
}
}
}
继续跟踪schedulerShouldRenderTransactions实现:
// FabricUIManagerBinding.cpp
void FabricUIManagerBinding::schedulerShouldRenderTransactions(
const std::shared_ptr<const MountingCoordinator>& mountingCoordinator) {
auto mountingManager =
getMountingManager("schedulerShouldRenderTransactions");
if (!mountingManager) {
return;
}
if (ReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid()) {
auto mountingTransaction = mountingCoordinator->pullTransaction(
/* willPerformAsynchronously = */ true);
if (mountingTransaction.has_value()) {
auto transaction = std::move(*mountingTransaction);
mountingManager->executeMount(transaction);
}
} else {
std::vector<MountingTransaction> pendingTransactions;
{
// 保留锁以访问待处理事务,但不要执行挂载操作,因为该方法可能会再次调用此方法。
//
// 当挂载管理器同步触发状态更新时(例如从 UI 线程提交时),此方法可能会被重入调用。
// 这是安全的,因为我们已经将同一surface ID 的所有事务合并到待处理事务列表中的单个事务中,
// 因此操作不会乱序执行。
std::unique_lock<std::mutex> lock(pendingTransactionsMutex_);
pendingTransactions_.swap(pendingTransactions);
}
for (auto& transaction : pendingTransactions) {
mountingManager->executeMount(transaction);
}
}
}
到这里,最重要的方法是executeMount。该方法负责将 C++ 层的 Shadow Tree 变更(MountingTransaction)转换为 Java 层的视图操作指令,并调度到 UI 线程执行。
具体说,就是将 C++ 的 ShadowViewMutation 转换为 Java 的 MountItem,并序列化传递给 Java 层。该方法的实现非常长,这里仅摘要一部分。源码react-native/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp:
void FabricMountingManager::executeMount(
const MountingTransaction& transaction) {
// 省略......
// 遍历 mutations,将 ShadowViewMutation(Create/Delete/Insert/Remove/Update)转换为 CppMountItem
for (const auto& mutation : mutations) {
auto parentTag = mutation.parentTag;
const auto& oldChildShadowView = mutation.oldChildShadowView;
const auto& newChildShadowView = mutation.newChildShadowView;
auto& mutationType = mutation.type;
auto& index = mutation.index;
bool isVirtual = mutation.mutatedViewIsVirtual();
switch (mutationType) {
case ShadowViewMutation::Create: {
bool shouldCreateView =
!allocatedViewTags.contains(newChildShadowView.tag);
if (shouldCreateView) {
cppCommonMountItems.push_back(
CppMountItem::CreateMountItem(newChildShadowView));
allocatedViewTags.insert(newChildShadowView.tag);
}
break;
}
case ShadowViewMutation::Remove: {
if (!isVirtual) {
cppCommonMountItems.push_back(
CppMountItem::RemoveMountItem(
parentTag, oldChildShadowView, index));
}
break;
}
case ShadowViewMutation::Delete: {
(maintainMutationOrder ? cppCommonMountItems : cppDeleteMountItems)
.push_back(CppMountItem::DeleteMountItem(oldChildShadowView));
if (allocatedViewTags.erase(oldChildShadowView.tag) != 1) {
LOG(ERROR) << "Emitting delete for unallocated view "
<< oldChildShadowView.tag;
}
break;
}
// 省略代码......
default: {
break;
}
}
}
}
// 现在我们已经掌握了所有必要的信息,包括挂载项的顺序,因此可以准确地知道需要分配多少空间。
auto [batchMountItemIntsSize, batchMountItemObjectsSize] = computeBufferSizes(
cppCommonMountItems,
cppDeleteMountItems,
cppUpdatePropsMountItems,
cppUpdateStateMountItems,
cppUpdatePaddingMountItems,
cppUpdateLayoutMountItems,
cppUpdateOverflowInsetMountItems,
cppUpdateEventEmitterMountItems);
static auto scheduleMountItem = JFabricUIManager::javaClassStatic()
->getMethod<void(
JMountItem::javaobject,
jint,
jlong,
jlong,
jlong,
jlong,
jlong,
jlong,
jlong,
jint)>("scheduleMountItem");
// 省略
// 调用 JFabricUIManager.createIntBufferBatchMountItem() 创建 Java 对象
// 将序列化数据传递给 Java 层
static auto createMountItemsIntBufferBatchContainer =
JFabricUIManager::javaClassStatic()
->getMethod<jni::alias_ref<JMountItem>(
jint, jintArray, jni::jtypeArray<jobject>, jint)>(
"createIntBufferBatchMountItem");
auto batch = createMountItemsIntBufferBatchContainer(
javaUIManager_,
surfaceId,
// If there are no items, we pass a nullptr instead of passing the
// object through the JNI
batchMountItemIntsSize > 0 ? buffer.ints : nullptr,
batchMountItemObjectsSize > 0 ? buffer.objects.get() : nullptr,
revisionNumber);
auto finishTransactionEndTime = telemetryTimePointNow();
// 调度到 UI 线程,将 BatchMountItem 发送到 Java 层
scheduleMountItem(
javaUIManager_,
batch.get(),
telemetry.getRevisionNumber(),
telemetryTimePointToMilliseconds(telemetry.getCommitStartTime()),
telemetryTimePointToMilliseconds(telemetry.getDiffStartTime()),
telemetryTimePointToMilliseconds(telemetry.getDiffEndTime()),
telemetryTimePointToMilliseconds(telemetry.getLayoutStartTime()),
telemetryTimePointToMilliseconds(telemetry.getLayoutEndTime()),
telemetryTimePointToMilliseconds(finishTransactionStartTime),
telemetryTimePointToMilliseconds(finishTransactionEndTime),
telemetry.getAffectedLayoutNodesCount());
env->DeleteLocalRef(buffer.ints);
}
可以看到,在此方法中反射调用了上层的scheduleMountItem,与我们前面分析的结果对接上了。
总的来说,该方法充当 C++ Shadow Tree 与 Java 原生视图之间的桥梁,将 React 的声明式变更转换为 Android 视图操作指令,并调度到 UI 线程执行,实现从虚拟树到真实视图的映射。
由于单章字数限制,这里将本文拆成上下两篇,下篇《React Native之Android端Fabric 架构源码分析(下)》