作者簡介? 原創(chuàng)微信公眾號郭霖 WeChat ID: guolin_blog
本篇來自程序媛fanfan_story的投稿,透過Android6.0源碼阳掐,分析了Activity加載View的過程,希望大家喜歡财骨。
fanfan_story的博客地址:
http://blog.csdn.net/zrf1335348191
認識Activity的布局
對于研究布局這種東西巡球,必須要掌握一些視圖工具壁酬,在這里推薦一個sdk查看視圖的工具sdk\tools\hierarchyviewer,隨意找一個界面去查看 activity 的 view視圖:
在這個 activity 界面中我把導航欄給隱藏了辖所,所以不存在導航欄惰说,根據(jù)這張圖的話大致可以看到一個 activity 的布局,再結(jié)合對?setContentView 的研究缘回,可以總結(jié)出 activity 的布局圖如下:
從這張 activity 的布局圖可以看到:一個 activity 對應(yīng)一個應(yīng)用窗口 mWindow吆视,應(yīng)用窗口 mWindow 包括 activity 的 頂級view是 mDecorView,mDecorView 包括 狀態(tài)欄statusbar和 導航欄navigationbar 以及要加載 activity 布局的view一一mDecorContentParent酥宴,該 view 又包括一個 標題欄titlebar 和 activity的內(nèi)容布局 contentparent啦吧。在 contentParent 中就是該 activity 的 view樹。
1. mWindow:Window對象幅虑,Window是一個抽象類丰滑,是 activity 的頂層外觀和行為的代理。會往 windowmanage 中添加該類的一個實例作為 頂層view倒庵。window 提供基本的UI代理,比如背景啊炫刷,標題區(qū)域啊擎宝,按鍵處理啊等等,Window 只有一個實現(xiàn)類 PhoneWindow浑玛,所以 mWindow對象 實際是 PhoneWindow對象绍申。當啟動一個activity的過程中會初始化一個屬于 Phonewindow 的 window對象。Phonewindow對象 的創(chuàng)建在activity 的 attach方法 中顾彰。
2. mDecor:DecorView對象极阅,繼承自 framelayout,是 window窗口 的 頂級view涨享,包含 window 的裝飾筋搏。類的定義位于 PhoneWindow.java 中
3. mDecorContentParent:DecorContentParent對象,實現(xiàn)類是 ActionbarOverlayLayout厕隧,屬于 activity 布局的 最外層view奔脐,包括標題欄和activity的內(nèi)容布局
4. mContentParent:activity 的內(nèi)容布局俄周,繼承自 ViewGroup,用來加載存放 activity 的 view樹髓迎,如果沒有標題欄峦朗,那么 mContentparent 的大小會和 mDecorContentParent 相等,以此類推
5. 導航欄:statusbar,對應(yīng)的 id 為 statusBarBackground排龄,在 PhoneWindow 中會加載波势,當 window屬性 發(fā)生改變時會刷新導航欄。但不論是導航欄和狀態(tài)欄橄维,從這個id也可以看出艰亮,PhoneWindow 只是加載他們的 background,即相當于只加載一個view的占位挣郭,先告訴應(yīng)用窗口迄埃,系統(tǒng)窗口要求將狀態(tài)欄和導航欄布局在這里,你不要占用兑障,但此時不會加載導航欄和狀態(tài)欄的view侄非,只是繪制背景而已。
6. 狀態(tài)欄:navigationbar,對應(yīng)的 id 為 navigationBarBackground流译,在 PhoneWindow 中會加載逞怨,當 window屬性 發(fā)生改變時會刷新狀態(tài)欄
7. 標題欄:titlebar,對于導航欄福澡,狀態(tài)欄和標題欄的存在與否叠赦,與 window 的屬性特征有關(guān),在加載 view 時所以會去判斷 window 的屬性特征革砸,進而決定是否要加載這三者除秀。
對 activity 的布局大致有個了解之后,就開始去分析 activity 啟動后加載view的流程
Activity加載View布局
對于 activity 的布局的加載大致分為兩部分算利,一部分是加載view册踩,另一部分是將view綁定到應(yīng)用窗口Window。其中這兩個步驟中將 view 綁定到 window 是在 啟動activity時 完成的操作效拭,是將 mDecor 綁定到 window暂吉。然后再往 mDecor 中添加 各種view。對于 activity的啟動過程 留待以后進行分析缎患,現(xiàn)在分析加載view一一始于 Activity.Java?的setContentView方法慕的,看一下加載view的流程。
可以看到代碼流程很簡單挤渔,從 Activity.java 的 setContentView方法 進入肮街,到 PhonewWindow.java 的 setContentView方法 進行一系列處理,接下來進入代碼進行分析
Activity.java 的 setContentView 方法
代碼路徑\Android\frameworks\base\core\java\android\app
源碼中對該方法的解釋是蚂蕴,從一個 layout 文件中取出 view 設(shè)置成 activity 的 content低散,該資源文件會被填充俯邓,并遍歷文件中的 所有view 添加到 activity。意思就是填充一個資源文件熔号,加載view稽鞭。做了兩件事兒:
一是 getWindow 獲取到 Window對象,然后去調(diào)用 Window 的 setContentView方法引镊。
二是 initWindowDecorActionbar()朦蕴,創(chuàng)建 actionbar對象,填充 mDecor 下的 actionbarView弟头,并把 view 加載上去(博主猜測是在 Window 的 setContentView方法 中只是填充一個 actionbar 的占位吩抓,然后 initWindowDecorActionbar() 完成 view 的加載)
重點研究第一步:getWindow().setContentView方法。
首先一個問題赴恨,為什么我要說 getWindow.setContentView 調(diào)用的是 PhoneWindow 中的setContentView方法疹娶?
解疑:查看getWindow方法:
publicWindowgetWindow() {
returnmWindow;}
返回的是 activity 的 mWindow對象,對于 mWindow對象 的創(chuàng)建也是在 Activity.java 中的 attach方法 中:
同時伦连,進入到 Window.java 中也可以看到這一點:
源碼中對于 Window類 的說明是:
Window 是一個抽象類雨饺,是最頂層的窗口的外觀和行為的代理,window 的實例應(yīng)該被作為最頂層的UI添加到 WindowManage?中惑淳。Window 提供了基本的ui额港,比如背景,標題區(qū)域歧焦,默認的按鍵處理過程等等移斩。Window 只有一個唯一的實現(xiàn)類 PhoneWindow,當需要 Window對象 時需要去初始化 PhoneWindow绢馍。
至此向瓷,對于 Activity 中的 mWindow對象 大致有了一個清晰的認識了:他是個 PhoneWindow對象,Window.java 中方法的實現(xiàn)在?PhoneWindow.java 中
PhoneWindow.java中的setContentView方法
代碼路徑\android\frameworks\base\core\java\com\android\internal\policy
先來總結(jié)一下代碼的流:
在新啟動一個 activity 時 mContentParent 還未綁定id痕貌,此時 mContentParent 為null风罩。從代碼流程圖中可以看出 setContentView 做了三件事:
installDecor 實例化 DecorView對象 和 mContentParent對象
填充 layout 文件
通知 activity 布局已經(jīng)改變
為什么說是通知 activity 布局已經(jīng)改變呢?這是因為在 Activity.java 的 attach方法 中 mWindow對象 設(shè)置了 callback 為this舵稠,所以在 getCallback 時獲取到的 cb 為當前與該 window 對應(yīng)的 activity。
PhoneWindow.java中的installDecor方法分析
實例化 DecorView對象 和 mContentParent對象
在創(chuàng)建一個 activity 時 mDecor 和 mContentParent 均為null
借助 generateDecor 方法實例化 mDecor入宦,即獲取到 activity 的 最頂級的view
借助 generateLayout 方法實例化 mContentParent對象哺徊,并且根據(jù) window 的不同 Feature 來選擇對應(yīng)的布局文件(總之,generatelayout 其實就是根據(jù)當前的 window 的特征屬性 feature 來加載內(nèi)容布局乾闰,并獲取到當前布局的 最外層view落追。也就是說
generatelayout 本質(zhì)就是根據(jù) activity 的 theme主題 來找到對應(yīng)的xml布局并且獲取到id為 content 的 ViewGroup賦給 mContentParent
獲取到 mDecorParent對象,并且根據(jù) getLocalFeature 獲取到的 Feature 來設(shè)置(這也就說明了在自定義Activity時為什么要將?getWindow.requestFeature方法 寫在 setContentView方法 之前)
對 title 進行隱藏或者是設(shè)置內(nèi)容的操作
如果需要切入切出動畫涯肩,那么就獲取到各種動畫資源
接下來對 installDecor 中某些代碼做一些分析:
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
用于對焦點的傳遞設(shè)置:只有當 子view 不想獲取焦點時 mDecor 才會去獲取焦點
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable)
去開啟初始化menu菜單的線程
在這里說明一句轿钠,為什么 requestFeature 要寫在 setContentView 前面巢钓,這是因為在調(diào)用 setContentView 時會獲取到 window 的各種 feature 進行一些判斷設(shè)置。
PhoneWindow.java中的generateLayout方法研究
第一步:首先是獲取到 window 的布局style
TypedArraya=getWindowStyle();
第二步:獲取到各種屬性并進行 requestFeature 的設(shè)置
第三步:通過獲取到的 window 的布局去獲取 window 的各種屬性疗垛,并根據(jù) window 的各種屬性去選擇不同的 layout 的文件症汹,比如標題欄是否隱藏,window 是懸浮窗還是全屏等等問題贷腕。當然因為在3.0和4.0以及5.0對于menukey的支持不同背镇,所以會有一個與版本相關(guān)的一個判斷。至于這個版本之間有什么不同可以參考總結(jié)說明中列出來的文件泽裳。
其實 generatelayout 就做了一件事瞒斩,那就是根據(jù) window 的各種屬性去獲取不同的xml文件。
總結(jié)
setContentView 執(zhí)行流程中主要涉及到3個類 PhoneWindow.java涮总,Activity.java 和 Window.java
Window 和 windowmanager 中的 各種feature 和 flag的style 對應(yīng)的各種含義以及動畫 style在\android\android\frameworks\base\core\res\res\values\attrs.xml 文件中有注釋說明
在 menu鍵 的設(shè)置中涉及到了版本問題胸囱,包括 3.0,4.0 和 5.0 分別有對應(yīng)的不同處理瀑梗,參考 \android\android\frameworks\base\core\java\android\os\Build.java 可以看到注釋有說明各版本有什么不同
至于為什么說 mDecor 是 最外層view烹笔,是因為在 generateLayout 方法中 mDecor 將填充該xml文件的 view一一mContentRoot 添加了進來。
Activity在啟動加載布局的操作
創(chuàng)建 DecorView 的布局:setContentView 的流程基本是用來創(chuàng)建 DecorView 的布局
將布局添加到 window 窗口:在 Activity 的啟動過程中夺克,會將應(yīng)用窗口添加到 WindowManager 中進行統(tǒng)一管理箕宙,以及綁定 DecorView
對于狀態(tài)欄和導航欄,是在每次 window 屬性發(fā)生變化時會去更新铺纽,但是只是設(shè)置了一個背景色柬帕,只是占位用,沒有加載這些view
文章原創(chuàng)作者GuoLin 書籍推薦
郭林大神原創(chuàng)android 書籍:《第一行代碼 android》