目錄
- 思維導(dǎo)圖
- 概述
- 參考
思維導(dǎo)圖
概述
- 初始化 PhoneWindow 和 WindowManager
- 初始化 DecorView
- ViewRootImpl 的創(chuàng)建和關(guān)聯(lián) DecorView
- 建立 PhoneWindow 和 WMS 之間的連接
- 建立與 SurfaceFlinger 之間的連接
- 申請(qǐng) Surface
- 正式繪制 View 并顯示
步驟一:初始化 PhoneWindow 和 WindowManager
我們知道,Activity 是在 ActivityThread 的 performLaunchActivity 中進(jìn)行創(chuàng)建的眯停,在創(chuàng)建完成之后就會(huì)調(diào)用其 attach 方法毛肋,它是先于 onCreate、onStart、onResume 等生命周期函數(shù)的,因此將 attach 方法作為這篇文章主線的開(kāi)頭:
// Activity#attach():
final void attach(...) {
attachBaseContext(context);
//初始化 PhoneWindow
mWindow = new PhoneWindow(this, window, activityConfigCallback);
//初始化 WindowManager
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
mWindowManager = mWindow.getWindowManager();
}
// Window#setWindowManager():
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);
}
attach() 方法就是 new 一個(gè) PhoneWindow 并且關(guān)聯(lián) WindowManager。
步驟二:初始化 DecorView
接下來(lái)就到了 onCreate 方法:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
public void setContentView(int layoutResID) {
installDecor();
mLayoutInflater.inflate(layoutResID, mContentParent)
}
這一步就是把我們的布局文件解析成 View 塞到 DecorView 的一個(gè) id 為 R.id.content 的 ContentView 中肴楷,DecorView 本身是一個(gè) FrameLayout,它還承載了 StatusBar敢课、NavigationBar 。
步驟三:ViewRootImpl 的創(chuàng)建和關(guān)聯(lián) DecorView
然后在 handleResumeActivity 中绷杜,通過(guò) WindowManager 的 addView 方法把 DecorView 添加進(jìn)去直秆,實(shí)際實(shí)現(xiàn)是 WindowManagerImpl 的 addView 方法,它里面再通過(guò) WindowManagerGlobal 的實(shí)例去 addView 的鞭盟,在它里面就會(huì) new 一個(gè) ViewRootImpl圾结,也就是說(shuō)最后是把 DecorView 傳給了 ViewRootImpl 的 setView 方法。ViewRootImpl 是 DecorView 的管理者齿诉,它負(fù)責(zé) View 樹(shù)的測(cè)量筝野、布局、繪制粤剧,以及通過(guò) Choreographer 來(lái)控制 View 的刷新歇竟。
步驟四:建立 PhoneWindow 和 WindowManagerService 之間的連接
WMS 是所有 Window 窗口的管理員,負(fù)責(zé) Window 的添加和刪除抵恋、Surface 的管理和事件派發(fā)等等焕议,因此每一個(gè) Activity 中的 PhoneWindow 對(duì)象如果需要顯示等操作,就必須要與 WMS 交互才能進(jìn)行弧关。
在 ViewRootImpl 的 setView 方法中盅安,會(huì)調(diào)用 requestLayout唤锉,并且通過(guò) WindowSession 的 addToDisplay 與 WMS 進(jìn)行交互。WMS 會(huì)為每一個(gè) Window 關(guān)聯(lián)一個(gè) WindowStatus别瞭。
步驟五:建立與 SurfaceFlinger 的連接
SurfaceFlinger 主要是進(jìn)行 Layer 的合成和渲染窿祥。
在 WindowStatus 中,會(huì)創(chuàng)建 SurfaceSession蝙寨,SurfaceSession 會(huì)在 Native 層構(gòu)造一個(gè) SurfaceComposerClient 對(duì)象晒衩,它是應(yīng)用程序與 SurfaceFlinger 溝通的橋梁。
步驟六:申請(qǐng) Surface
經(jīng)過(guò)步驟四和步驟五之后籽慢,ViewRootImpl 與 WMS浸遗、SurfaceFlinger 都已經(jīng)建立起連接,但此時(shí) View 還沒(méi)顯示出來(lái)箱亿,我們知道跛锌,所有的 UI 最終都要通過(guò) Surface 來(lái)顯示,那么 Surface 是什么時(shí)候創(chuàng)建的呢届惋?
這就要回到前面所說(shuō)的 ViewRootImpl 的 requestLayout 方法了髓帽,首先會(huì) checkThread 檢查是否是主線程,然后調(diào)用 scheduleTraversals 方法脑豹,scheduleTraversals 方法會(huì)先設(shè)置同步屏障郑藏,然后通過(guò) Choreographer 類(lèi)在下一幀到來(lái)時(shí)去執(zhí)行 doTraversal 方法。簡(jiǎn)單來(lái)說(shuō)瘩欺,Choreographer 內(nèi)部會(huì)接受來(lái)自 SurfaceFlinger 發(fā)出的 Vsync 垂直同步信號(hào)必盖,這個(gè)信號(hào)周期一般是 16ms 左右。doTraversal 方法首先會(huì)先移除同步屏障俱饿,然后 performTraversals 真正進(jìn)行 View 的繪制流程歌粥,即調(diào)用 performMeasure、performLayout拍埠、performDraw失驶。不過(guò)在它們之前,會(huì)先調(diào)用 relayoutWindow 通過(guò) WindowSession 與 WMS 進(jìn)行交互枣购,即把 Java 層創(chuàng)建的 Surface 與 Native 層的 Surface 關(guān)聯(lián)起來(lái)嬉探。
步驟七:正式繪制 View 并顯示
接下來(lái)就是正式繪制 View 了,從 performTraversals 開(kāi)始棉圈,Measure涩堤、Layout、Draw 三步走分瘾。
第一步是獲取 DecorView 的寬高的 MeasureSpec 然后執(zhí)行 performMeasure 流程定躏。MeasureSpec 簡(jiǎn)單來(lái)說(shuō)就是一個(gè) int 值,高 2 位表示測(cè)量模式,低 30 位用來(lái)表示大小痊远。策略模式有三種垮抗,EXACTLY、AT_MOST碧聪、UNSPECIFIED冒版。EXACTLY 對(duì)應(yīng)為 match_parent 和具體數(shù)值的情況,表示父容器已經(jīng)確定 View 的大谐炎恕辞嗡;AT_MOST 對(duì)應(yīng) wrap_content,表示父容器規(guī)定 View 最大只能是 SpecSize滞造;UNSPECIFIED 表示不限定測(cè)量模式续室,父容器不對(duì) View 做任何限制,這種適用于系統(tǒng)內(nèi)部谒养。接著說(shuō)挺狰,performMeasure 中會(huì)去調(diào)用 DecorView 的 measure 方法,這個(gè)是 View 里面的方法并且是 final 的买窟,它里面會(huì)把參數(shù)透?jìng)鹘o onMeasure 方法丰泊,這個(gè)方法是可以重寫(xiě)的,也就是我們可以干預(yù) View 的測(cè)量過(guò)程始绍。在 onMeasure 中也物,會(huì)通過(guò) getDefaultSize 獲取到寬高的默認(rèn)值科平,然后調(diào)用 setMeasureDimension 將獲取的值進(jìn)行設(shè)置。在 getDefaultSize 中终蒂,無(wú)論是 EXACTLY 還是 AT_MOST缰猴,都會(huì)返回 MeasureSpec 中的大小丹墨,這個(gè) SpecSize 就是測(cè)量后的最終結(jié)果龟虎。至于 UNSPECIFIED 的情況俘种,則會(huì)返回一個(gè)建議的最小值,這個(gè)值和子元素設(shè)置的最小值以及它的背景大小有關(guān)篇亭。從這個(gè)默認(rèn)實(shí)現(xiàn)來(lái)看缠捌,如果我們自定義一個(gè) View 不重寫(xiě)它的 onMeasure 方法锄贷,那么 warp_content 和 match_parent 一樣译蒂。所以 DecorView 重寫(xiě)了 onMeasure 函數(shù),它本身是一個(gè) FrameLayout谊却,所以最后也會(huì)調(diào)用到 FrameLayout 的 onMeasure 函數(shù)柔昼,作為一個(gè) ViewGroup,都會(huì)遍歷子 View 并調(diào)用子 View 的 measure 方法炎辨。這樣便實(shí)現(xiàn)了層層遞歸調(diào)用到了每個(gè)子 View 的 onMeasure 方法進(jìn)行測(cè)量捕透。
第二步是執(zhí)行 performLayout 的流程,也就是調(diào)用到 DecorView 的 layout 方法,也就是 View 里面的方法乙嘀,如果 View 大小發(fā)生變化末购,則會(huì)回調(diào) onSizeChanged 方法,如果 View 狀態(tài)發(fā)生變化虎谢,則會(huì)回調(diào) onLayout 方法盟榴,這個(gè)方法在 View 中是空實(shí)現(xiàn),因此需要看 DecorView 的父容器 FrameLayout 的 onLayout 方法婴噩,這個(gè)方法就是遍歷子 View 調(diào)用其 layout 方法進(jìn)行布局擎场,子 View 的 layout 方法被調(diào)用的時(shí)候,它的 onLayout 方法又會(huì)被調(diào)用几莽,這樣就布局完了所有的 View迅办。
第三步就是 performDraw 方法了,里面會(huì)調(diào)用 drawSoftware 方法章蚣,這個(gè)方法需要先通過(guò) mSurface lockCanvas 獲取一個(gè) Canvas 對(duì)象站欺,作為參數(shù)傳給 DecorView 的 draw 方法。這個(gè)方法調(diào)用的是 View 的 draw 方法究驴,先繪制 View 背景镊绪,然后繪制 View 的內(nèi)容,如果有子 View 則會(huì)調(diào)用子 View 的 draw 方法洒忧,層層遞歸調(diào)用蝴韭,最終完成繪制。
完成這三步之后熙侍,會(huì)在 ActivityThread 的 handleResumeActivity 最后調(diào)用 Activity 的 makeVisible榄鉴,這個(gè)方法就是將 DecorView 設(shè)置為可見(jiàn)狀態(tài)。