從setContentView了解Android UI繪制流程
初學(xué)android的朋友可能會(huì)有這樣一種疑問(wèn)甜害,為什么在setContentView方法里指定對(duì)應(yīng)的layout資源,就能把對(duì)應(yīng)的布局加載到屏幕上池凄。那么,咱們現(xiàn)在就開(kāi)始從源碼來(lái)分析這樣一個(gè)問(wèn)題馅精。
首先胚鸯,在onCreate方法里面,調(diào)用了setContentView方法减江,這個(gè)方法是來(lái)自Activity的。我們進(jìn)入到Activity的源碼:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
這里調(diào)用了getWindow的setContentView方法捻爷,那getWindow返回了一個(gè)Window對(duì)象,而Window是一個(gè)抽象類(lèi)份企,它的唯一子類(lèi)叫做PhoneWindow,那么這個(gè)window是什么時(shí)候被賦值的呢也榄?是在attach里面直接new出來(lái)的
mWindow = new PhoneWindow(this, window, activityConfigCallback)
我們進(jìn)入到PhoneWindow看一下setContentView方法。
這個(gè)方法主要做了兩件事:
1.installDecor
installDecor這個(gè)方法干了兩件事
1.1 generateDecor
這里實(shí)例化了一個(gè)DecorView ,DecorView繼承自FrameLayout,用來(lái)裝載我們的頁(yè)面布局
1.2 generateLayout
如果沒(méi)有特殊情況的話甜紫,是將R.layout.screen_simple這樣一個(gè)布局加載到DecorView中
布局文件如下:是一個(gè)縱向布局 ViewStup用于擺放action bar降宅,而FrameLayout用于擺放我們布局文件中的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
這一步驟完成之后,mContentParent就不為null了,mContentParent實(shí)際上是一個(gè)ViewGroup囚霸,它對(duì)應(yīng)的類(lèi)型是R.id.content腰根,在R.layout.screen_simple中對(duì)應(yīng)的實(shí)際上就是一個(gè)FrameLayout。
2.將setContentView傳入的layout解析并繪制
主要代碼就是 mLayoutInflater.inflate(layoutResID, mContentParent);
我們來(lái)看一下這個(gè)方法:
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
這個(gè)方法最終返回一個(gè)View拓型,也就是向mContentParent中添加子View额嘿。
主要代碼 :
View temp = createViewFromTag(root, name, inflaterContext, attrs);
temp.setLayoutParams(params);
rInflateChildren(parser, temp, attrs, true);
root.addView(temp, params);
其中涉及到的xml解析可見(jiàn)下圖
這樣,我們整個(gè)布局就加載到了對(duì)應(yīng)的Activity當(dāng)中了劣挫,那么册养,布局是什么時(shí)候開(kāi)始繪制,如何繪制到屏幕上的呢压固?請(qǐng)看下回分解球拦。
總結(jié):最終Activity的層次結(jié)構(gòu)可以總結(jié)為下圖: