Android-ReactNative渲染流程

注册组件

在RN项目中必须使用AppRegistry.registerComponent(appkey,component)来注册组件。在上一篇中的runJSBundle里面,加载js文件后,交给JSC运行(evaluateSourceCode函数),就会开始执行index.js,执行里面的代码,在index.js里面就会调用AppRegistry来注册组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
registerComponent(
appKey: string,
componentProvider: ComponentProvider,
section?: boolean,
): string {
// 为该appkey准备了一个runnable
runnables[appKey] = {
componentProvider,
run: appParameters => {
// appParameters启动参数,来自原生调用传入的
// 开始渲染
renderApplication(
componentProviderInstrumentationHook(componentProvider),
appParameters.initialProps,
appParameters.rootTag,
wrapperComponentProvider && wrapperComponentProvider(appParameters),
appParameters.fabric,
);
},
};
if (section) {
sections[appKey] = runnables[appKey];
}
return appKey;
},

启动组件

在上一篇说到,当Context创建完毕后,会启动js组件(defaultJSEntryPoint函数),通过调用js函数AppRegister.runApplication来启动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
runApplication(appKey: string, appParameters: any): void {
invariant(
runnables[appKey] && runnables[appKey].run,
'Application ' +
appKey +
' has not been registered.\n\n' +
"Hint: This error often happens when you're running the packager " +
'(local dev server) from a wrong folder. For example you have ' +
'multiple apps and the packager is still running for the app you ' +
'were working on before.\nIf this is the case, simply kill the old ' +
'packager instance (e.g. close the packager terminal window) ' +
'and start the packager in the correct app folder (e.g. cd into app ' +
"folder and run 'npm start').\n\n" +
'This error can also happen due to a require() error during ' +
'initialization or failure to call AppRegistry.registerComponent.\n\n',
);

// 运行该appkey注册的runnable
runnables[appKey].run(appParameters);
}

解析组件

通过ReactNativeRenderer来解析组件视图,然后会调用组件的render方法获取渲染内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function renderApplication<Props: Object>(
RootComponent: React.ComponentType<Props>,
initialProps: Props,
rootTag: any,
WrapperComponent?: ?React.ComponentType<*>,
fabric?: boolean,
) {
let renderable = (
<AppContainer rootTag={rootTag} WrapperComponent={WrapperComponent}>
<RootComponent {...initialProps} rootTag={rootTag} />
</AppContainer>
);
if (
RootComponent.prototype != null &&
RootComponent.prototype.unstable_isAsyncReactComponent === true
) {
const AsyncMode = React.unstable_AsyncMode;
renderable = <AsyncMode>{renderable}</AsyncMode>;
}
if (fabric) {
require('ReactFabric').render(renderable, rootTag);
} else {
//
require('ReactNative').render(renderable, rootTag);
}
}
加载原生组件

此处拿DrawerLayoutAndroid组件来举例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 // 在DrawerLayoutAndroid组件的render函数中返回一个AndroidDrawerLayout组件,这是它的真正实现,是一个原生组件。
render: function() {
...
return (
<AndroidDrawerLayout
{...this.props}
ref={RK_DRAWER_REF}
drawerWidth={this.props.drawerWidth}
drawerPosition={this.props.drawerPosition}
drawerLockMode={this.props.drawerLockMode}
style={[styles.base, this.props.style]}
onDrawerSlide={this._onDrawerSlide}
onDrawerOpen={this._onDrawerOpen}
onDrawerClose={this._onDrawerClose}
onDrawerStateChanged={this._onDrawerStateChanged}>
{childrenWrapper}
{drawerViewWrapper}
</AndroidDrawerLayout>
);
},
requireNativeComponent (Js层)

在js加载的时候会先注册该组件的属性设置回调,然后在真正创建该组件的时候调用该回调获取组件的属性配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 通过requireNativeComponent函数可以加载指定的原生组件
const AndroidDrawerLayout = requireNativeComponent('AndroidDrawerLayout');

const requireNativeComponent = (uiViewClassName: string): string =>
// 注册该组件对应的属性设置回调,在创建该组件时调用
createReactNativeComponentClass(uiViewClassName, () => {
const viewConfig = UIManager[uiViewClassName];
...
return viewConfig;
});

// 注册在viewConfigCallbacks中
exports.register = function(name: string, callback: ViewConfigGetter): string {
viewConfigCallbacks.set(name, callback);
return name;
};
创建VIew
createInstance (JS层)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
createInstance: function(
type,
props,
rootContainerInstance,
hostContext,
internalInstanceHandle
) {
var tag = allocateTag(),
// 获取注册的属性设置回调
viewConfig = ReactNativeViewConfigRegistry.get(type);
type = diffProperties(
null,
emptyObject$1,
props,
viewConfig.validAttributes
);
// 调用native的UIManager模块的createView方法来创建
UIManager.createView(
tag,
viewConfig.uiViewClassName,
rootContainerInstance,
type
);
rootContainerInstance = new ReactNativeFiberHostComponent(tag, viewConfig);
instanceCache[tag] = internalInstanceHandle;
instanceProps[tag] = props;
return rootContainerInstance;
},
调用Java Module方法 (Java层)

调用Java层UIManagerModule的createView方法来创建对应原生视图,具体调用原理可以看上一篇的Android-ReactNative通信流程

1
2
3
4
5
6
7
8
9
10
@ReactMethod
public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
if (DEBUG) {
String message =
"(UIManager.createView) tag: " + tag + ", class: " + className + ", props: " + props;
FLog.d(ReactConstants.TAG, message);
PrinterHolder.getPrinter().logMessage(ReactDebugOverlayTags.UI_MANAGER, message);
}
mUIImplementation.createView(tag, className, rootViewTag, props);
}
将创建view的请求添加到队列中 (Java层)

UIManagerModule的createView方法最终会走到UIVIewOperationQueue中,在该类中维护了一个操作队列,主线程不停的执行该对象中的操作。由于UIManagerModule.createView是在native消息线程中执行的,所以会将创建View的请求封装成一个操作加入到队列中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

public void enqueueCreateView(
ThemedReactContext themedContext,
int viewReactTag,
String viewClassName,
@Nullable ReactStylesDiffMap initialProps) {
synchronized (mNonBatchedOperationsLock) {
mNonBatchedOperations.addLast(
new CreateViewOperation(
themedContext,
viewReactTag,
viewClassName,
initialProps));
}
}
操作队列的执行 (Java层)

当Activity触发onResume时,UIViewOperationQueue会向ReactChoreographer中添加一个回调。

1
2
3
4
5
6
/* package */ void resumeFrameCallback() {
mIsDispatchUIFrameCallbackEnqueued = true;
// 添加回调
ReactChoreographer.getInstance()
.postFrameCallback(ReactChoreographer.CallbackType.DISPATCH_UI, mDispatchUIFrameCallback);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public synchronized void postFrameCallback(
CallbackType type,
ChoreographerCompat.FrameCallback frameCallback) {
// 将添加的回调加入到回调队列的尾部
mCallbackQueues[type.getOrder()].addLast(frameCallback);
mTotalCallbacks++;
Assertions.assertCondition(mTotalCallbacks > 0);
if (!mHasPostedCallback) {
// 向内部的Choreographer添加一个回调,实际上就是在主线程的Handler中执行mReactChoreographerDispatcher的runnable
mChoreographer.postFrameCallback(mReactChoreographerDispatcher);
mHasPostedCallback = true;
}
}

public void postFrameCallback(FrameCallback callbackWrapper) {
if (IS_JELLYBEAN_OR_HIGHER) {
choreographerPostFrameCallback(callbackWrapper.getFrameCallback());
} else {
mHandler.postDelayed(callbackWrapper.getRunnable(), 0);
}
}

// 实际上执行的是doFrame方法,在该方法中会遍历回调队列,执行所有回调的doFrame方法。
private class ReactChoreographerDispatcher extends ChoreographerCompat.FrameCallback {
@Override
public void doFrame(long frameTimeNanos) {
synchronized (ReactChoreographer.this) {
mHasPostedCallback = false;
for (int i = 0; i < mCallbackQueues.length; i++) {
int initialLength = mCallbackQueues[i].size();
for (int callback = 0; callback < initialLength; callback++) {
mCallbackQueues[i].removeFirst().doFrame(frameTimeNanos);
mTotalCallbacks--;
}
}
maybeRemoveFrameCallback();
}
}
}

也就是说当Activity触发OnResume,UIViewOperationQueue添加一个callback到回调队列中,并向主线程添加一个处理该回调队列的runnable,主线程执行该callback的doFrame方法。在该callback结束的时候,它将自己再次添加到回调队列中,然后回调队列向主线程添加执行runnable,主线程执行改callback。这样将无限的循环下去,直到该callback被移除,比如说当onPause发生时。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
private class DispatchUIFrameCallback extends GuardedFrameCallback {

private static final int FRAME_TIME_MS = 16;
private final int mMinTimeLeftInFrameForNonBatchedOperationMs;

private DispatchUIFrameCallback(
ReactContext reactContext, int minTimeLeftInFrameForNonBatchedOperationMs) {
super(reactContext);
mMinTimeLeftInFrameForNonBatchedOperationMs = minTimeLeftInFrameForNonBatchedOperationMs;
}

@Override
public void doFrameGuarded(long frameTimeNanos) {
try {
dispatchPendingNonBatchedOperations(frameTimeNanos);
} finally {
}
// 处理UI操作队列
flushPendingBatches();
// 再次添加自己,无限循环的执行
ReactChoreographer.getInstance().postFrameCallback(
ReactChoreographer.CallbackType.DISPATCH_UI, this);
}

private void dispatchPendingNonBatchedOperations(long frameTimeNanos) {
while (true) {
// frameTimeNanos是主线程开始处理回调队列的时间,此处计算的目前为止,主线程此次执行该回调队列的时间
long timeLeftInFrame = FRAME_TIME_MS - ((System.nanoTime() - frameTimeNanos) / 1000000);
//mMinTimeLeftInFrameForNonBatchedOperationMs默认为8
// 主线程处理一条消息的时间不要超过8秒,如果超过,则停止,等待下次消息再处理。
if (timeLeftInFrame < mMinTimeLeftInFrameForNonBatchedOperationMs) {
break;
}

UIOperation nextOperation;
synchronized (mNonBatchedOperationsLock) {
// 如果操作队列空了,则退出while
if (mNonBatchedOperations.isEmpty()) {
break;
}
// 取出队列对头的操作
nextOperation = mNonBatchedOperations.pollFirst();
}
try {
long nonBatchedExecutionStartTime = SystemClock.uptimeMillis();
// 执行操作
nextOperation.execute();
mNonBatchedExecutionTotalTime +=
SystemClock.uptimeMillis() - nonBatchedExecutionStartTime;
} catch (Exception e) {
mIsInIllegalUIState = true;
throw e;
}
}
}
}
真正的创建view (Java层)

执行CreateViewOperation的execute方法,具体在NativeViewHierarchyManager的createView中。ViewManager是在ReactPackage的createViewManagers中注册的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public synchronized void createView(
ThemedReactContext themedContext,
int tag,
String className,
@Nullable ReactStylesDiffMap initialProps) {
UiThreadUtil.assertOnUiThread();
try {
// 通过类名找到注册的ViewManager
ViewManager viewManager = mViewManagers.get(className);
// 通过指定的ViewManager来创建View
View view = viewManager.createView(themedContext, mJSResponderHandler);
mTagsToViews.put(tag, view);
mTagsToViewManagers.put(tag, viewManager);
view.setId(tag);
if (initialProps != null) {
// 更新属性
viewManager.updateProperties(view, initialProps);
}
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_VIEW);
}
}
添加View到视图
finalizeInitialChildren (C++层)

在createInstance后,会就调用finalizeInitialChildren方法将该View添加到父布局中。

1
2
3
4
5
6
7
8
9
finalizeInitialChildren: function(parentInstance) {
if (0 === parentInstance._children.length) return !1;
var nativeTags = parentInstance._children.map(function(child) {
return "number" === typeof child ? child : child._nativeTag;
});
// 和创建一样,调用的是native方法
UIManager.setChildren(parentInstance._nativeTag, nativeTags);
return !1;
},

和上面一样通过Bridge走到c++,然后通过c++走到了java层,最终执行了UIManager.setChildren方法。

1
2
3
4
5
6
@ReactMethod
public void setChildren(
int viewTag,
ReadableArray childrenTags) {
mUIImplementation.setChildren(viewTag, childrenTags);
}

在setChildren方法中最终会添加一个ManageChildrenOperation操作到UI操作队列中,这个操作队列和创建View时的操作队列不是同一个。这个操作队列专门处理UI的更新操作。

1
2
3
4
5
6
7
8
public void enqueueManageChildren(
int reactTag,
@Nullable int[] indicesToRemove,
@Nullable ViewAtIndex[] viewsToAdd,
@Nullable int[] tagsToDelete) {
mOperations.add(
new ManageChildrenOperation(reactTag, indicesToRemove, viewsToAdd, tagsToDelete));
}

这个队列中的操作是在c++调用onBatchComplete时执行,而onBatchComplete是在c++处理完js对native方法调用请求的时候会触发的。

onBatchComplete (Java层)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public void onBatchComplete() {
int batchId = mBatchId;
mBatchId++;
for (UIManagerModuleListener listener : mListeners) {
listener.willDispatchViewUpdates(this);
}
try {
// 在该方法中会添加一个runable到DispatchUIRunnable中去,然后在DispatchUIFrameCallback中的flushPendingBatches方法会执行该runnable
mUIImplementation.dispatchViewUpdates(batchId);
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
flushPendingBatches (Java层)

此时执行的runnable是在onBatchComplete中添加的runnable,在该runnable中会处理UI操作队列中的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Runnable runOperations =
new Runnable() {
@Override
public void run() {
try {
long runStartTime = SystemClock.uptimeMillis();
if (nonBatchedOperations != null) {
for (UIOperation op : nonBatchedOperations) {
op.execute();
}
}
if (batchedOperations != null) {
for (UIOperation op : batchedOperations) {
op.execute();
}
}
if (mIsProfilingNextBatch && mProfiledBatchCommitStartTime == 0) {
mProfiledBatchCommitStartTime = commitStartTime;
mProfiledBatchLayoutTime = layoutTime;
mProfiledBatchDispatchViewUpdatesTime = dispatchViewUpdatesTime;
mProfiledBatchRunStartTime = runStartTime;
}
mNativeViewHierarchyManager.clearLayoutAnimation();
if (mViewHierarchyUpdateDebugListener != null) {
mViewHierarchyUpdateDebugListener.onViewHierarchyUpdateFinished();
}
} catch (Exception e) {
mIsInIllegalUIState = true;
throw e;
} finally {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
}
};
添加到父布局 (Java层)

然后就会执行上面setChildren中添加的ManageChildrenOperation操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public synchronized void manageChildren(
int tag,
@Nullable int[] indicesToRemove,
@Nullable ViewAtIndex[] viewsToAdd,
@Nullable int[] tagsToDelete) {
UiThreadUtil.assertOnUiThread();
final ViewGroup viewToManage = (ViewGroup) mTagsToViews.get(tag);
final ViewGroupManager viewManager = (ViewGroupManager) resolveViewManager(tag);
int lastIndexToRemove = viewManager.getChildCount(viewToManage);
if (indicesToRemove != null) {
for (int i = indicesToRemove.length - 1; i >= 0; i--) {
int indexToRemove = indicesToRemove[i];
View viewToRemove = viewManager.getChildAt(viewToManage, indexToRemove);

if (mLayoutAnimationEnabled &&
mLayoutAnimator.shouldAnimateLayout(viewToRemove) &&
arrayContains(tagsToDelete, viewToRemove.getId())) {
// The view will be removed and dropped by the 'delete' layout animation
// instead, so do nothing
} else {
viewManager.removeViewAt(viewToManage, indexToRemove);
}
lastIndexToRemove = indexToRemove;
}
}

if (viewsToAdd != null) {
for (int i = 0; i < viewsToAdd.length; i++) {
ViewAtIndex viewAtIndex = viewsToAdd[i];
View viewToAdd = mTagsToViews.get(viewAtIndex.mTag);
if (viewToAdd == null) {
}
// 添加view到父布局中
viewManager.addView(viewToManage, viewToAdd, viewAtIndex.mIndex);
}
}

if (tagsToDelete != null) {
for (int i = 0; i < tagsToDelete.length; i++) {
int tagToDelete = tagsToDelete[i];
final View viewToDestroy = mTagsToViews.get(tagToDelete);
if (viewToDestroy == null) {
}

if (mLayoutAnimationEnabled &&
mLayoutAnimator.shouldAnimateLayout(viewToDestroy)) {
mLayoutAnimator.deleteView(viewToDestroy, new LayoutAnimationListener() {
@Override
public void onAnimationEnd() {
viewManager.removeView(viewToManage, viewToDestroy);
dropView(viewToDestroy);
}
});
} else {
dropView(viewToDestroy);
}
}
}
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×