基于Android6.0的Activity加載View源碼分析

作者簡介? 原創微信公眾號郭霖 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 界面中我把導航欄給隱藏了,所以不存在導航欄,根據這張圖的話大致可以看到一個 activity 的布局,再結合對?setContentView 的研究,可以總結出 activity 的布局圖如下:

從這張 activity 的布局圖可以看到:一個 activity 對應一個應用窗口 mWindow,應用窗口 mWindow 包括 activity 的 頂級view是 mDecorView,mDecorView 包括 狀態欄statusbar和 導航欄navigationbar 以及要加載 activity 布局的view一一mDecorContentParent,該 view 又包括一個 標題欄titlebar 和 activity的內容布局 contentparent。在 contentParent 中就是該 activity 的 view樹。

1. mWindow:Window對象,Window是一個抽象類,是 activity 的頂層外觀和行為的代理。會往 windowmanage 中添加該類的一個實例作為 頂層view。window 提供基本的UI代理,比如背景啊,標題區域啊,按鍵處理啊等等,Window 只有一個實現類 PhoneWindow,所以 mWindow對象 實際是 PhoneWindow對象。當啟動一個activity的過程中會初始化一個屬于 Phonewindow 的 window對象。Phonewindow對象 的創建在activity 的 attach方法 中。

2. mDecor:DecorView對象,繼承自 framelayout,是 window窗口 的 頂級view,包含 window 的裝飾。類的定義位于 PhoneWindow.java 中

3. mDecorContentParent:DecorContentParent對象,實現類是 ActionbarOverlayLayout,屬于 activity 布局的 最外層view,包括標題欄和activity的內容布局

4. mContentParent:activity 的內容布局,繼承自 ViewGroup,用來加載存放 activity 的 view樹,如果沒有標題欄,那么 mContentparent 的大小會和 mDecorContentParent 相等,以此類推

5. 導航欄:statusbar,對應的 id 為 statusBarBackground,在 PhoneWindow 中會加載,當 window屬性 發生改變時會刷新導航欄。但不論是導航欄和狀態欄,從這個id也可以看出,PhoneWindow 只是加載他們的 background,即相當于只加載一個view的占位,先告訴應用窗口,系統窗口要求將狀態欄和導航欄布局在這里,你不要占用,但此時不會加載導航欄和狀態欄的view,只是繪制背景而已。

6. 狀態欄:navigationbar,對應的 id 為 navigationBarBackground,在 PhoneWindow 中會加載,當 window屬性 發生改變時會刷新狀態欄

7. 標題欄:titlebar,對于導航欄,狀態欄和標題欄的存在與否,與 window 的屬性特征有關,在加載 view 時所以會去判斷 window 的屬性特征,進而決定是否要加載這三者。

對 activity 的布局大致有個了解之后,就開始去分析 activity 啟動后加載view的流程

Activity加載View布局

對于 activity 的布局的加載大致分為兩部分,一部分是加載view,另一部分是將view綁定到應用窗口Window。其中這兩個步驟中將 view 綁定到 window 是在 啟動activity時 完成的操作,是將 mDecor 綁定到 window。然后再往 mDecor 中添加 各種view。對于 activity的啟動過程 留待以后進行分析,現在分析加載view一一始于 Activity.Java?的setContentView方法,看一下加載view的流程。

可以看到代碼流程很簡單,從 Activity.java 的 setContentView方法 進入,到 PhonewWindow.java 的 setContentView方法 進行一系列處理,接下來進入代碼進行分析

Activity.java 的 setContentView 方法

代碼路徑\Android\frameworks\base\core\java\android\app

源碼中對該方法的解釋是,從一個 layout 文件中取出 view 設置成 activity 的 content,該資源文件會被填充,并遍歷文件中的 所有view 添加到 activity。意思就是填充一個資源文件,加載view。做了兩件事兒:

一是 getWindow 獲取到 Window對象,然后去調用 Window 的 setContentView方法。

二是 initWindowDecorActionbar(),創建 actionbar對象,填充 mDecor 下的 actionbarView,并把 view 加載上去(博主猜測是在 Window 的 setContentView方法 中只是填充一個 actionbar 的占位,然后 initWindowDecorActionbar() 完成 view 的加載)

重點研究第一步:getWindow().setContentView方法。

首先一個問題,為什么我要說 getWindow.setContentView 調用的是 PhoneWindow 中的setContentView方法?

解疑:查看getWindow方法:

publicWindowgetWindow() {

returnmWindow;}

返回的是 activity 的 mWindow對象,對于 mWindow對象 的創建也是在 Activity.java 中的 attach方法 中:

同時,進入到 Window.java 中也可以看到這一點:

源碼中對于 Window類 的說明是:

Window 是一個抽象類,是最頂層的窗口的外觀和行為的代理,window 的實例應該被作為最頂層的UI添加到 WindowManage?中。Window 提供了基本的ui,比如背景,標題區域,默認的按鍵處理過程等等。Window 只有一個唯一的實現類 PhoneWindow,當需要 Window對象 時需要去初始化 PhoneWindow。

至此,對于 Activity 中的 mWindow對象 大致有了一個清晰的認識了:他是個 PhoneWindow對象,Window.java 中方法的實現在?PhoneWindow.java 中

PhoneWindow.java中的setContentView方法

代碼路徑\android\frameworks\base\core\java\com\android\internal\policy

先來總結一下代碼的流:

在新啟動一個 activity 時 mContentParent 還未綁定id,此時 mContentParent 為null。從代碼流程圖中可以看出 setContentView 做了三件事:

installDecor 實例化 DecorView對象 和 mContentParent對象

填充 layout 文件

通知 activity 布局已經改變

為什么說是通知 activity 布局已經改變呢?這是因為在 Activity.java 的 attach方法 中 mWindow對象 設置了 callback 為this,所以在 getCallback 時獲取到的 cb 為當前與該 window 對應的 activity。

PhoneWindow.java中的installDecor方法分析

實例化 DecorView對象 和 mContentParent對象

在創建一個 activity 時 mDecor 和 mContentParent 均為null

借助 generateDecor 方法實例化 mDecor,即獲取到 activity 的 最頂級的view

借助 generateLayout 方法實例化 mContentParent對象,并且根據 window 的不同 Feature 來選擇對應的布局文件(總之,generatelayout 其實就是根據當前的 window 的特征屬性 feature 來加載內容布局,并獲取到當前布局的 最外層view。也就是說

generatelayout 本質就是根據 activity 的 theme主題 來找到對應的xml布局并且獲取到id為 content 的 ViewGroup賦給 mContentParent

獲取到 mDecorParent對象,并且根據 getLocalFeature 獲取到的 Feature 來設置(這也就說明了在自定義Activity時為什么要將?getWindow.requestFeature方法 寫在 setContentView方法 之前)

對 title 進行隱藏或者是設置內容的操作

如果需要切入切出動畫,那么就獲取到各種動畫資源

接下來對 installDecor 中某些代碼做一些分析:

mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

用于對焦點的傳遞設置:只有當 子view 不想獲取焦點時 mDecor 才會去獲取焦點

mDecor.postOnAnimation(mInvalidatePanelMenuRunnable)

去開啟初始化menu菜單的線程

在這里說明一句,為什么 requestFeature 要寫在 setContentView 前面,這是因為在調用 setContentView 時會獲取到 window 的各種 feature 進行一些判斷設置。

PhoneWindow.java中的generateLayout方法研究

第一步:首先是獲取到 window 的布局style

TypedArraya=getWindowStyle();

第二步:獲取到各種屬性并進行 requestFeature 的設置

第三步:通過獲取到的 window 的布局去獲取 window 的各種屬性,并根據 window 的各種屬性去選擇不同的 layout 的文件,比如標題欄是否隱藏,window 是懸浮窗還是全屏等等問題。當然因為在3.0和4.0以及5.0對于menukey的支持不同,所以會有一個與版本相關的一個判斷。至于這個版本之間有什么不同可以參考總結說明中列出來的文件。

其實 generatelayout 就做了一件事,那就是根據 window 的各種屬性去獲取不同的xml文件。

總結

setContentView 執行流程中主要涉及到3個類 PhoneWindow.java,Activity.java 和 Window.java

Window 和 windowmanager 中的 各種feature 和 flag的style 對應的各種含義以及動畫 style在\android\android\frameworks\base\core\res\res\values\attrs.xml 文件中有注釋說明

在 menu鍵 的設置中涉及到了版本問題,包括 3.0,4.0 和 5.0 分別有對應的不同處理,參考 \android\android\frameworks\base\core\java\android\os\Build.java 可以看到注釋有說明各版本有什么不同

至于為什么說 mDecor 是 最外層view,是因為在 generateLayout 方法中 mDecor 將填充該xml文件的 view一一mContentRoot 添加了進來。

Activity在啟動加載布局的操作

創建 DecorView 的布局:setContentView 的流程基本是用來創建 DecorView 的布局

將布局添加到 window 窗口:在 Activity 的啟動過程中,會將應用窗口添加到 WindowManager 中進行統一管理,以及綁定 DecorView

對于狀態欄和導航欄,是在每次 window 屬性發生變化時會去更新,但是只是設置了一個背景色,只是占位用,沒有加載這些view


文章原創作者GuoLin 書籍推薦

郭林大神原創android 書籍:《第一行代碼 android》

淘寶鏈接:

https://s.click.taobao.com/t?e=m%3D2%26s%3DgKUfuKdAZKocQipKwQzePOeEDrYVVa64K7Vc7tFgwiHjf2vlNIV67p2n%2BQBNMyE6Rku8%2Bpj6eJall3bs%2B3NRhNHnsKI%2BqxhyM0iVZhTFBom4YIorMPnmg8G0g2OJi%2FzmXHfenomYtn5EW9vzeG8LzfPUwktUBEmkxg5p7bh%2BFbQ%3D&pvid=10_106.6.161.154_3367_1490163222155

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,634評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,653評論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,835評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,235評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,459評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,000評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,819評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,004評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,257評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,717評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,003評論 2 374

推薦閱讀更多精彩內容