ViewRoot指的是ViewRootImpi,它是連接WindowManager和DecorView的橋梁速蕊,view的三大流程(測量娘赴、布局、繪制)都需要ViewRoot來完成诽表。
- 它是view的根隅肥,他控制View的測量袄简、布局绿语、繪制
- 它持有WindowSession通過Binder與WMS通信。
目錄
- ViewRoot在哪里被創(chuàng)建又如何關(guān)聯(lián)DecorView和WindowManager的
- ViewRoot是如何完成view的三大流程
- DecorView的基礎(chǔ)概念
1. ViewRoot在哪里被創(chuàng)建又如何關(guān)聯(lián)DecorView和WindowManager的
ViewRootImpl是在WindowManagerGlobal的addView()發(fā)方法中被創(chuàng)建的吕粹。當Activity在ActivityThread中被創(chuàng)建后緊接著會將DecorView添加到Window中,同時也會創(chuàng)建ViewRootImpl匹耕,并將ViewRootImpi和DecorView關(guān)聯(lián)起來。
下面為WindowManagerGlobal中addView()的部分源碼:
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow){
...
synchronized (mLock) {
...
//創(chuàng)建ViewRootImp
root = new ViewRootImpl(view.getContext(), display);
...
}
try {
//關(guān)聯(lián)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()方法還會先調(diào)用requestLayout()煤傍,完成布局的第一次layout過程损趋,然后調(diào)用addToDisplay(),來添加Window(mWindowSession.addToDisplay調(diào)用的是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()方法調(diào)用是通過scheduleTraversals()中handler去異步調(diào)用mTraversalRunnable接口該蒋失,最后該接口中的run()方法又調(diào)用了doTraversal()方法才調(diào)起了performTraverse()桐玻。
void doTraversal() {
if (mTraversalScheduled) {
...
try {
performTraversals();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
...
}
}
ViewRoot的performTraversals()是該類的核心,因為真正開始繪制是從調(diào)用這個方法開始铣卡。
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的基礎(chǔ)概念
DecorView是界面的頂級View,一般它是由一個豎向的LinearLayout和狀態(tài)欄組合成(一些特殊機型還會有導航欄)蝉仇,LinearLayout布局中有標題欄和內(nèi)容欄(content)組合而成(可參考下圖)。
- 內(nèi)容欄是一個FrameLayout布局
- Activity的
setConentView()
方法就是在內(nèi)容欄中增加View -
findViewById(android.R.id.content)
獲取的是內(nèi)容欄 -
contentView.getChildAt(0)
獲取的是當前Activity布局文件的跟布局沉迹,也就是我們在layout文件設(shè)置的頂層的view害驹。
下圖為DecorView的層級關(guān)系圖: