????????DecorView是一個應(yīng)用窗口的根容器泄朴,它本質(zhì)上是一個FrameLayout罢吃。DecorView有唯一一個子View,它是一個垂直LinearLayout宴偿,包含兩個子元素湘捎,一個是TitleView(ActionBar的容器),另一個是ContentView(窗口內(nèi)容的容器)窄刘。
????????關(guān)于ContentView窥妇,它是一個FrameLayout(android.R.id.content),我們平常用的setContentView就是設(shè)置它的子View娩践。上圖還表達(dá)了每個Activity都與一個Window(具體來說是PhoneWindow)相關(guān)聯(lián)活翩,用戶界面則由Window所承載烹骨。
????????Window即窗口,這個概念在Android Framework中的實(shí)現(xiàn)為android.view.Window這個抽象類材泄,這個抽象類是對Android系統(tǒng)中的窗口的抽象沮焕。在介紹這個類之前,我們先來看看究竟什么是窗口呢拉宗?
????????實(shí)際上峦树,窗口是一個宏觀的思想,它是屏幕上用于繪制各種UI元素及響應(yīng)用戶輸入事件的一個矩形區(qū)域旦事。通常具備以下兩個特點(diǎn):
? ? ? ? 1魁巩、獨(dú)立繪制,不與其它界面相互影響族檬;
? ? ? ? 2歪赢、不會觸發(fā)其它界面的輸入事件;
????在Android系統(tǒng)中单料,窗口是獨(dú)占一個Surface實(shí)例的顯示區(qū)域暑竟,每個窗口的Surface由WindowManagerService分配碟摆。我們可以把Surface看作一塊畫布,應(yīng)用可以通過Canvas或OpenGL在其上面作畫。畫好之后盆昙,通過SurfaceFlinger將多塊Surface按照特定的順序(即Z-order)進(jìn)行混合婆瓜,而后輸出到FrameBuffer中桦沉,這樣用戶界面就得以顯示定枷。
????????android.view.Window這個抽象類可以看做Android中對窗口這一宏觀概念所做的約定,而PhoneWindow這個類是Framework為我們提供的Android窗口概念的具體實(shí)現(xiàn)沉颂。接下來我們先來介紹一下android.view.Window這個抽象類条摸。
????????這個抽象類包含了三個核心組件:
? ? ? ? 1、WindowManager.LayoutParams: 窗口的布局參數(shù)铸屉;
? ? ? ? 2钉蒲、Callback: 窗口的回調(diào)接口,通常由Activity實(shí)現(xiàn)彻坛;
? ? ? ? 3顷啼、ViewTree: 窗口所承載的控件樹。
Android中Window的具體實(shí)現(xiàn)(也是唯一實(shí)現(xiàn))——PhoneWindow昌屉。
????????PhoneWindow這個類是Framework為我們提供的Android窗口的具體實(shí)現(xiàn)钙蒙。我們平時調(diào)用setContentView()方法設(shè)置Activity的用戶界面時,實(shí)際上就完成了對所關(guān)聯(lián)的PhoneWindow的ViewTree的設(shè)置间驮。我們還可以通過Activity類的requestWindowFeature()方法來定制Activity關(guān)聯(lián)PhoneWindow的外觀躬厌,這個方法實(shí)際上做的是把我們所請求的窗口外觀特性存儲到了PhoneWindow的mFeatures成員中,在窗口繪制階段生成外觀模板時竞帽,會根據(jù)mFeatures的值繪制特定外觀烤咧。
????????setContentView()方法只是完成了Activity的ContentView的創(chuàng)建偏陪,而并沒有執(zhí)行View的繪制流程。當(dāng)我們自定義Activity繼承自android.app.Activity時候煮嫌,調(diào)用的setContentView()方法是Activity類的,源碼如下:
????????getWindow()方法會返回Activity所關(guān)聯(lián)的PhoneWindow抱虐,也就是說昌阿,實(shí)際上調(diào)用到了PhoneWindow的setContentView()方法,源碼如下:
????????LayoutInflater.inflate()
????????PhoneWindow的setContentView()方法中調(diào)用了LayoutInflater的inflate()方法來填充布局恳邀,這個方法的源碼如下:
????????在PhoneWindow的setContentView()方法中傳入了decorView作為LayoutInflater.inflate()的root參數(shù)懦冰,我們可以看到,通過層層調(diào)用谣沸,最終調(diào)用的是inflate(XmlPullParser, ViewGroup, boolean)方法來填充布局刷钢。這個方法的源碼如下:
先對merge標(biāo)簽進(jìn)行單獨(dú)處理,調(diào)用rInflate()方法來遞歸填充布局乳附。這個方法的源碼如下:
????????上面的inflate()和rInflate()方法中都調(diào)用了rInflateChildren()方法内地,這個方法的源碼如下:
rInflateChildren()方法實(shí)際上調(diào)用了rInflate()方法。setContentView()的整體執(zhí)行流程我們就分析完了赋除,至此我們已經(jīng)完成了Activity的ContentView的創(chuàng)建與設(shè)置工作阱缓。