通常我們在onCreate中會呼叫setContentView方法,如下:


跳轉到getWindow().setContentView(layoutResID)如下:

Window型別的繼承樹如下:



DecorView實際上是作為Activity上的檢視的最頂層View,而我們自己的佈局則是上圖粉色區域,外面還包含著一層,稱之為contentParent,從名字上看也是取得很貼切,嗯還是進入原始碼看看一下是不是上圖描述的那樣,如下:



至此可以看到最頂層佈局,以及我們自己的佈局的復佈局都已建立好了,回到上圖示記B 的地方,可以看到呼叫了 mLayoutInflater.inflate(layoutResID, mContentParent); 這個layoutResID就是我們自己的佈局的id,呼叫完這一句我們自己的佈局也被建立出來了,到這裡你應該會有一個疑問:Activity的整個View檢視都被建立好了,那麼接下來應該是要繪製這個檢視才對,我第一次看這個原始碼的時候也是有這個疑問,同時還犯了一個錯誤,我試圖在mLayoutInflater.inflate(layoutResID, mContentParent);這句之後查詢開啟繪製試圖的程式碼,檢視原始碼我根本就找不到,一下子就懵逼了,如下:

其實這是我忽略了一個事實,這個setCotentView 是在onCreate被呼叫的這個時候View是不能見,真正能見的是在onResum時候,對哦,恍然大悟!!如果你有閱讀之前的那篇Activity生命週期回撥是如何被回撥的?應該會知道onResume何時開始被呼叫,如下:



進入wm.addView看看如何,呼叫的是它的實現類WindowManagerImpl的addView如下:







performTraversals方法的程式碼是在是太長了,這裡我不截圖,這個方法裡面呼叫了三個關鍵的方法:performMeasure方法開啟檢視的測量流程,performLayout方法開啟了檢視的佈局流程,performDraw開啟了檢視的繪製流程,這3個方面的具體細節我準備在其他篇章來介紹,這3個流程走完,檢視就會被真正的繪製完成。到此setContentView的工作是如何一步一步被現實的,你是否有一個比較深的理解了,回顧一下前面講的東西,可以總結如下:
1.setContentView只是將Activity的整個View檢視建立好,放在一邊而已,而執行建立View檢視的則是PhoneWindow
2.在Activity在準備轉換成Resume狀態的之際,即呼叫handleResumeActivity,會將最頂層View——DecorView兜兜轉轉傳到WindowManagerGlobal 手中
3.DecorView在WindowManagerGlobal 手中,首先先新增進View陣列方便管理同時會為這個DecorView也可以說是這個檢視建立一個ViewRootImpl
4.ViewRootImpl 將呼叫setView 將DecorView傳入,開啟繪製之旅