當我們新建一個工程的時候,選擇生成一個Activity,AS會自動給我們生成一個介面,那麼這個介面是怎麼生成的呢,下面我們就來分析一下:
Activity中的程式碼:
@Overrideprotected
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);}
複製程式碼
XML中的程式碼:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp"
android:gravity="top"
android:hint="這是一個EditTextView"
android:inputType="textMultiLine"
android:maxLines="20"
android:minLines="6"
android:textSize="30sp" />
</RelativeLayout>
複製程式碼
用Hierarchy viewer工具來檢視一下結構圖: ![@P8]6~ZC7~MJ~LJFG(DPBWA.png](http://upload-images.jianshu.io/upload_images/587163-e85daee233003243.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
DecorView以及它的子View一目瞭然,先看下SetContentView()的實現:
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}}
複製程式碼
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
//mContentParent 是放置窗體內容的容器,也就是我們 setContentView()
//時所加入的 View 檢視樹
private ViewGroup mContentParent;
複製程式碼
DecorView是PhoneWindow的一個內部類,同時DecorView也是Activiy的頂級View,一般來說DecorView的內部包括導航欄(NavigationBar)和狀態列(StatusBar),但這個會隨著主題的變化而發生改變。剛開始mContentParent的值是null,所以會走installDecor():
if (mDecor == null) {
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
// Set up decor part of UI to ignore fitsSystemWindows if appropriate.
mDecor.makeOptionalFitsSystemWindows();
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(R.id.decor_content_parent);
複製程式碼
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
複製程式碼
在installDecor()裡面通過呼叫generateDecor()方法來初始化DecorView,此時DecorView什麼都沒有,只是一個空的FrameLayout,往下走,來到generateLayout(mDecor),跳過一些主題佈局設定,直接來到關鍵程式碼:
mDecor.startChanging();
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
複製程式碼
/** * The ID that the main layout in the XML layout file should have. */
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
複製程式碼
DecorView通過generateLayout(mDecor)載入到具體的佈局檔案,具體的佈局檔案和系統版本以及主題有關,ID_ANDROID_CONTENT對應的即是R.id.content,也是我們通過SetContentView()中設定的佈局id,走完installDecor(),我們繼續看PhoneWindow中的SetContentView()方法,
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
複製程式碼
接下來就簡單了,mLayoutInflater.inflate(layoutResID, mContentParent),因為前面通過installDecor()建立了DecorView,因此這一步就是將Activity的佈局(layoutResID)新增到mContentParent中了,到這裡為止,Activity的佈局檔案就已經新增到DecorView裡面了,繼續看SetcontentView():
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
複製程式碼
由於Activity實現了Window的Callback介面,
並且Activity的佈局檔案已經新增到DecorView裡的mContentParent裡了,當執行cb.onContentChanged()後,Activity就會回撥onContentChanged()方法,由於Activity的onContentChanged()是個空實現,我們可以在子Activity中處理這個回撥處理相應邏輯,到這裡為止DecorView就已經被建立並初始化完畢。