天天看點

從源碼的角度說說Activity的setContentView的原理

我們在Activity開發的時候天天會用到這個方法,有時候還需要根據需求在setContentView調用的時候做一些動作,是以我們就需要知道它内部是如何工作的,我們來一起看一下:

setContentView有三個重載方法:

他們實際都在調用getWindow方法傳回的Window對象的setContentView方法,那getWindow對象傳回的是誰呢?

我們可以看到getWindow傳回的是一個mWindows的對象,那麼它在哪被指派的呢?通過查找我們可以找到在Activity的attach方法中有這麼一段:

也就是說繼續往下看,發現PolicyManager.makeNewWindow内部确實這樣的:

好,那我們找找sPolicy又是誰:

我們可以在PolicyManager方法内看到靜态代碼塊以及它的一些屬性:

也就是說,sPolicy對象是類com.android.internal.policy.impl.Policy的一個執行個體,OK,我們進入這個類看一下它的makeNewWindow方法,噢噢,是這樣啊:

原來那個getWindow傳回的是PhoneWindow對象,setContentView調用的則是PhoneWindow的setContentView,OK,說了這麼多重點就是看下PhoneWindow的setContentView方法是如何工作的:

PhoneWindow的setContentView的重載方法内部有些不同,我們先看參數為int的setContentView:

我們隻看重點部分,都是通過LayoutInflater的inflate的方法加載的,是不是很熟悉呢?inflate方法的第二個參數是mContentParent,就是說要把這個layoutResID的這個布局添加到mContentParent中,那麼mContentParent就是我們的主布局了,從代碼中也可以看出來:

好,入口的東西都分析的差不多了,着重看一下LayoutInflater的inflate的工作原理,我們常用的方法是這3個:

其實它們都沒做什麼,主要做工作的是它:

這段代碼比較多,我們挑一下重點看:

這段代碼就是說通過createViewFromTag方法生成臨時View對象,然後如果View生成成功,給它産生一個預設的LayoutParams對象附在上面,最後判斷root是否為空,決定是否要将這個臨時View添加到root之上,好,接下來,我們的重點是createViewFromTag方法:

這麼多代碼,其實我們的重點是這部分:

我們可以看到,剛開始會交給mFactory2、mFactory、mPrivateFactory這三個View工廠來進行處理,這三個對象都是通過構造方法設定進來的,如下:

這個構造方法在哪裡被調用我們先不去看,我們可以繼續我們的重點:

這裡的意思是,如果這個Tag是沒有( . )的話,那就是說這個tag是android提供的預設的控件,像View,TextView,Button等等。否則,就是其它情況了,我們先看預設沒有( . )的情況:

請注意這個方法的第二個參數android.view.,然後我們進入方法内部:

這段代碼其實重點就是通過ClassLoader的loadClass方法将類加載進來,然後通過反射的方式擷取它的構造方法進行執行個體化,然後基本功能就完成了。有的同學可能會注意到這裡有個mFilter屬性,這個屬性是用來定義這個類是否允許被加載的。

好,以上就是最基本的Inflate加載過程,其實實際過程不是這樣的,我們将在下一章檢視詳細的加載過程。