要說Android view加載流程,首先,我們需要清楚的理解什麼是View、Window、Activity 以及三着有着什麼樣的關係。
一、什麼是Activity?
看看源碼中對Activity的描述:
* An activity is a single, focused thing that the user can do. Almost all
* activities interact with the user, so the Activity class takes care of
* creating a window for you in which you can place your UI with
* {@link #setContentView}. While activities are often presented to the user
* as full-screen windows
Activity是 用戶操作的可視化界面;它爲用戶提供了一個放置視圖和交互操作的窗口。採用setContentView的方法提供。
因此,可以理解Activity、Window、View三者關係爲。Activity提供Window ,View被添加到Window中。
以刷牆舉例:
Activity可以理解爲房間,Window就是房間內的牆面, 我們在牆面上可以刷各種不同的圖案,這些圖案就是View。
二、Activity View的加載流程
1、Activity在被創建之初,調用了attach方法,這個時候,爲Activity創建了一個PhoneWindow, 並且爲PhoneWindow設置了事件交互的回掉。
2、緊接着Activity的onCreate()方法被回掉。這裏也就到了我們經常複寫方法,我們在OnCreate()之中,調用setContentView(id)。
3、在setContentView(), PhoneWindow 創建了一個頂級視圖 DecorView (FrameLayout)的子類。
4、緊接着,DecorView會依據一些feature(類似NO_ACTICON_BAR)來,添加一個layout。這個Layout中包含了Title、content。其中content也是FrameLayout,也就是我們在setContentView(id),將視圖添加的父容器。
所以我們必須要在setContentView之前設置
實現全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
實現無標題欄(但有系統自帶的任務欄):
requestWindowFeature(Window.FEATURE_NO_TITLE);
更加直觀的可以看作爲:
我門操作的所有View都是在contentView這裏,contentView作爲父容器,其id爲固定的 android.id.content.
三、源碼分析
查看Activity的attach 方法
可以看出這個時候創建了PhoneWindow的實例。
接下來,Activity生命週期會到onCreate(),我們在onCreate方法中,調用了setContentView方法
跟進setContentView方法,看看源碼做了什麼
繼續,調用了PhoneWindow的setContentView
重點在installDecor()方法:
我們看看 mDecor 的初始化:
mDecor 是DecorView的實例,DecorView又是FrameLayout的子類:
我們回到installDecor方法,繼續往下查看generateLayout:
generateLayout()方法中,先對一系列的feature進行了判讀對比,和backgroud 顏色獲取等,然後通過以上feature加載一個layoutRes到decorView中。
然後在layoutRes,中找到 ID_ANDROID_CONTENT = com.android.internal.R.id.content 的FrameLayout 作爲我們setContentView 的容器。
此處框出的位置,就是我們返回的父容器。這裏很明顯返回的是ViewGroup, 就怎麼認定他是FrameLayout這個子類呢??
很簡單,對上訴的幾個resource點擊查看,發現全都是FrameLayout..
再次回到PhoneWindow#installDecor, 可以看到
mContentParent = generateLayout(mDecor);
在PhoneWindow#installDecor繼續往下看,可以看到對Title Icon這些的賦值之類。
返回到setContentView中:將我們的layoutId 解析爲View,加入到mContentParent。
mLayoutInflater.inflate(layoutResID, mContentParent);
我們在看看看LayoutInflater.inflate的過程:
其實就是解析XML ,更加xml解析爲View並添加到視圖關係中。
問題:view是如何根據我們的類名不同而創建的各種不同的View呢?
繼續跟進以上代碼,最終發現調用到了
依據類名反射創建, 到此,真個View的加載過程就完成了。
總結:
1、Activity在被創建之初,調用了attach方法,這個時候,爲Activity創建了一個PhoneWindow, 並且爲PhoneWindow設置了事件交互的回掉。
2、緊接着Activity的onCreate()方法被回掉。這裏也就到了我們經常複寫方法,我們在OnCreate()之中,調用setContentView(id)。
3、在setContentView(), PhoneWindow 創建了一個頂級視圖 DecorView (FrameLayout)的子類。
4、緊接着,DecorView會依據一些feature(類似NO_ACTICON_BAR)來,添加一個layout。這個Layout中包含了Title、content。
其中content也是FrameLayout
5、然後再將我們的setContentView()的layoutId解析爲View 添加到這個contentView中。
接下來, 又是如何被繪製到屏幕上的呢?請敬請等待下一章 Android View的繪製流程。