View的层级结构
ActivityThread的performLaunchActivity方法
我们知道,在Activity的创建流程中,在ActivityThread的performLaunchActivity方法中调用了Activity的attach方法,在attach方法里创建了PhoneWindow,然后调用setWindowManager给PhoneWindow设置了WindowManager,这是我们需要理解这一切的前提。
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
...
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
通过以上,我们记住PhoneWindow的mWindowManager是WindowManagerImpl。
Activity的setContentView方法
在performLaunchActivity方法的最后会回调Activity的onCreate方法,我们知道,在onCreate流程中会创建出PhoneWindow的DecorView:
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//DecorView的创建
installDecor();
} ...
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
...
} else {
//自定义xml布局的View加载
mLayoutInflater.inflate(layoutResID, mContentParent);
}
...
}
```
* #### ActivityThread的handleResumeActivity方法
performLaunchActivity流程之后接着会调用handleResumeActivity流程:
@Override
public void handleResumeActivity(IBinder token, ...) {
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
...
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
} else ...
}
} else if ...
...
}
```
ViewManager是WindowManager实现的接口,可以看到,这里调用了WindowManager,也就是WindowManagerImpl的addView方法,第一个参数就是要添加的View,也就是DecorView:
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
...
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
```
mGlobal是WindowManagerGlobal:
```
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
public static WindowManagerGlobal getInstance() {
synchronized (WindowManagerGlobal.class) {
if (sDefaultWindowManager == null) {
sDefaultWindowManager = new WindowManagerGlobal();
}
return sDefaultWindowManager;
}
}
```
可见,Android中所有的界面Window的DecorView都是通过同一个WindowManagerGlobal添加的。
* #### WindowManagerGlobal的addView方法
```
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
...
ViewRootImpl root;
View panelParentView = null;
//单例且有异步需求,因此这里需要同步
synchronized (mLock) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
```
我们或许在学习过程中都听过ViewRootImpl的名字,原来它是在这里创建的,它的setView方法如下:
```
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
...
mAttachInfo.mRootView = view;
...
mAdded = true;
...
requestLayout();
...
view.assignParent(this);
...
}
}
}
```
可以看到这里调用了requestLayout方法,对于这个方法我们应该有些眼熟,正是这个方法开启了绘制流程,我们下面会讲到。
assignParent方法的意义是什么呢?
```
void assignParent(ViewParent parent) {
if (mParent == null) {
mParent = parent;
} else if (parent == null) {
mParent = null;
} else {
throw new RuntimeException("view " + this + " being added, but"
+ " it already has a parent");
}
}
```
它给View的mParent方法赋值为ViewRootImpl本身,这是为了在View中调用requestLayout方法时可以回调到ViewRootImpl中(我们有时会通过手动调用requestLayout来触发界面的刷新和变化,像setLayoutParams这一类API内部也会调用requestLayout方法来刷新绘制):
```
//View中的requestLayout方法
public void requestLayout() {
...
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
...
}
```
可见,这里会调用mParent,也就是ViewRootImpl的requestLayout方法,这会触发自上而下的绘制流程。
* #### 总结
至此,我们总结一下View的层级结构:
1. 所有的Window(即Activity和Dialog中的PhoneWindow)都有一个ViewRootImpl,这些ViewRootImpl会被放到WindowManagerGlobal的mRoots(一个ArrayList)中保存,WindowManagerGlobal是单例,负责管理所有的ViewRootImpl。
2. ViewRootImpl中的mView就是DecorView。
3. DecorView中的mContenParent用来盛放我们xml布局中解析加载出的所有View(不在本篇讨论)。
通过上面的分析,我们知道了对于一个Activity来说,它内部持有了一个PhoneWindow,PhoneWindow内部又持有一个DecorView,而在handleResumeActivity流程中,WindowManagerImpl会创建ViewRootImpl,然后把DecorView赋值到它的mView上,DecorView是一个FrameLayout,自定义的xml布局中的根View会被添加到它的mContentParent中,这就是整个View层的结构。
ViewRootImpl的requestLayout方法
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
调用scheduleTraversals方法:
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
...
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
}
Choreographer的postCallback方逻辑中不管是走哪一路最终都会走到scheduleVsyncLocked中:
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
mDisplayEventReceiver是FrameDisplayEventReceiver实例,scheduleVsync方法的实现在FrameDisplayEventReceiver的父类DisplayEventReceiver中实现:
public void scheduleVsync() {
...
nativeScheduleVsync(mReceiverPtr);
...
}
nativeScheduleVsync会绑定屏幕刷新信号,在刷新信号到来时,会执行FrameDisplayEventReceiver的run方法,其中会调用doFrame方法,在doFrame方法中会调用:
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks方法中会按照Choreographer.CALLBACK_TRAVERSAL查找mCallbackQueues中的CallbackRecord然后执行它的run方法,CallbackRecord是在前面mChoreographer.postCallback传入的,Choreographer.CALLBACK_TRAVERSAL对应的也就是ViewRootImpl中的mTraversalRunnable:
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
可见最终调用的是doTraversal方法,它内部会调用performTraversals方法:
private void performTraversals() {
// cache mView since it is used so much below...
final View host = mView;
...
dispatchApplyInsets(host);
...
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
performLayout(lp, mWidth, mHeight);
...
performDraw();
...
}
performMeasure方法中:
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
if (mView == null) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
可以看到从这里进入到DecorView的measure流程,performLayout和performDraw也是同理的逻辑,也就是说三大绘制流程就是在这里依次触发的。