ViewRoot指的是ViewRootImpi,它是连接WindowManager和DecorView的桥梁,view的三大流程(测量、布局、绘制)都需要ViewRoot来完成。
- 它是view的根,他控制View的测量、布局、绘制
- 它持有WindowSession通过Binder与WMS通信。
目录
- ViewRoot在哪里被创建又如何关联DecorView和WindowManager的
- ViewRoot是如何完成view的三大流程
- DecorView的基础概念
1. ViewRoot在哪里被创建又如何关联DecorView和WindowManager的
ViewRootImpl是在WindowManagerGlobal的addView()发方法中被创建的。当Activity在ActivityThread中被创建后紧接着会将DecorView添加到Window中,同时也会创建ViewRootImpl,并将ViewRootImpi和DecorView关联起来。
下面为WindowManagerGlobal中addView()的部分源码:
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow){
...
synchronized (mLock) {
...
//创建ViewRootImp
root = new ViewRootImpl(view.getContext(), display);
...
}
try {
//关联WindowManager和DocorView
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
...
throw e;
}
}
下面为ViewRoot的setView()的部分源码
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
...
mView = view;
...
requestLayout();
...
try {
...
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel);
} catch (RemoteException e) {
...
}
}
}
在setView中传入的view
就是DecorView他被赋值给mView
这个会在performTraversals()中赋值给host
用于参与顶层view的测量和绘制。setView()方法还会先调用requestLayout(),完成布局的第一次layout过程,然后调用addToDisplay(),来添加Window(mWindowSession.addToDisplay调用的是Session的addToDisplay()方法)。
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets,
InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outInputChannel);
}
2. ViewRoot是如何完成view的三大流程
performTraversals()方法调用是通过scheduleTraversals()中handler去异步调用mTraversalRunnable接口该,最后该接口中的run()方法又调用了doTraversal()方法才调起了performTraverse()。
void doTraversal() {
if (mTraversalScheduled) {
...
try {
performTraversals();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
...
}
}
ViewRoot的performTraversals()是该类的核心,因为真正开始绘制是从调用这个方法开始。
performTraversals()部分源码:
private void performTraversals() {
//将DecorView赋值给host,用于view的测量、布局和绘制
final View host = mView;
if (!mStopped) {
...
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
}
...
if (didLayout) {
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
...
}
if (!cancelDraw && !newSurface) {
...
performDraw();
}
...
}
3. DecorView的基础概念
DecorView是界面的顶级View,一般它是由一个竖向的LinearLayout和状态栏组合成(一些特殊机型还会有导航栏),LinearLayout布局中有标题栏和内容栏(content)组合而成(可参考下图)。
- 内容栏是一个FrameLayout布局
- Activity的
setConentView()
方法就是在内容栏中增加View -
findViewById(android.R.id.content)
获取的是内容栏 -
contentView.getChildAt(0)
获取的是当前Activity布局文件的跟布局,也就是我们在layout文件设置的顶层的view。
下图为DecorView的层级关系图: