Activity -- setContentView
public void setContentView(View view) {
getWindow().setContentView(view);
initWindowDecorActionBar();
}
public Window getWindow() {
return mWindow;
}
final void attach(虎谢。脑融。。) {
...
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
}
在Activity的
setContentView
方法中調(diào)用了Window對應(yīng)的方法,Window本身是一個(gè)抽象類吊履,這里它的實(shí)現(xiàn)類是PhoneWindow,實(shí)際上調(diào)用的是PhoneWindow的setContentView
方法调鬓。
PhoneWindow -- setContentView
ViewGroup mContentParent;
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor(); //注釋1
} 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();
}
mContentParentExplicitlySet = true;
}
第一次調(diào)用的時(shí)候
mContentParent
為null艇炎,會執(zhí)行installDecor()
方法,在該方法中會創(chuàng)建mContentParent
;繼續(xù)執(zhí)行下面會把傳入的布局添加到mContentParent
中:mLayoutInflater.inflate(layoutResID, mContentParent);
//注釋1
private void installDecor() {
...
if (mDecor == null) {
mDecor = generateDecor(-1);
...
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
...
}
}
在
installDecor
方法中腾窝,會創(chuàng)建mDecor
(DecorView)和mContentParent
protected DecorView generateDecor(int featureId) {
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext().getResources());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
return new DecorView(context, featureId, this, getAttributes());
}
public class DecorView extends FrameLayout
直接
new DecorView
冕臭,DecorView
本質(zhì)是一個(gè)FrameLayout
。
protected ViewGroup generateLayout(DecorView decor) {
......
//根據(jù)設(shè)置的feature來選擇Activity的根部局
int layoutResource;
int features = getLocalFeatures();
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
setCloseOnSwipeEnabled(true);
} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_title_icons;
}
removeFeature(FEATURE_ACTION_BAR);
}
......
else {
layoutResource = R.layout.screen_simple;
}
mDecor.startChanging();
//往DecorView加載根部局
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
//找到內(nèi)容布局:不管選擇哪個(gè)根部局燕锥,內(nèi)容布局id都設(shè)置為ID_ANDROID_CONTENT這個(gè)參數(shù)值
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
return contentParent;
}
public abstract class Window{
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
}
根據(jù)
feature
來選擇Activity不同的布局,然后將布局添加到mDecor
中悯蝉,不管是哪種布局归形,內(nèi)容的布局id都是ID_ANDROID_CONTENT
,然后獲取內(nèi)容布局賦值給contentParent鼻由。
R.layout.screen_simple
<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>
R.layout.screen_simple
添加到DecorView中暇榴,DecorView在PhoneWindow中,所以通過findViewById(ID_ANDROID_CON)
獲取到的是FrameLayout返回給mContentParent
蕉世。通過setContentView
設(shè)置布局就是往mContentParent
里面添加內(nèi)容蔼紧。它本質(zhì)是一個(gè)FrameLayout。
布局層級圖
我們打開一個(gè)應(yīng)用狠轻,最外層是一個(gè)PhoneWindow奸例,它里層是一個(gè)DecorView,本質(zhì)就是一個(gè)FrameLayout向楼,然后它里層是一個(gè)LinearLayout查吊,是一個(gè)垂直方向的,上面是延時(shí)加載的ActionBar湖蜕,因?yàn)锳ctivity可能沒有actionBar逻卖,所以用ViewStub布局;下面是一個(gè)FrameLayout昭抒,我們通過
setContentView
設(shè)置的布局评也,就是往該FrameLayout中添加內(nèi)容。