在Activity和FragmentActivity中都会用到setContentView(R.layout.activity_main); 进入SetContentView方法可以看到:
/**
* 从布局资源中设置activity内容。资源被加载,然后添加所有顶级views到activity中。
*
* @param layoutResID Resource ID to be inflated.
*
* @see #setContentView(android.view.View)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
其中,getWindow()方法如下,
private Window mWindow;
public Window getWindow() {
return mWindow;
}
Window是个抽象类,必须得有子类实现才可以使用。搜索”mWindow =“可以看到 mWindow初始化实现的是PhoneWindow对象:
mWindow = new PhoneWindow(this, window);
PhoneWindow是com.android.internal.policy.PhoneWindow,继承Window:
/**
/* activity的主窗口构造方法
/**
public PhoneWindow(Context context, Window preservedWindow) {
this(context);
// 只有主acitivity窗口使用decor context,所有其他的window依 赖赋予它们的context
//所以这里有一个mUseDecorContext布尔值,标记可以使用DecorContext,在generateDecor(int featureId)方法中判断
mUseDecorContext = true;
if (preservedWindow != null) {
mDecor = (DecorView) preservedWindow.getDecorView();
mElevation = preservedWindow.getElevation();
mLoadElevation = false;
mForceDecorInstall = true;
getAttributes().token = preservedWindow.getAttributes().token;
}
boolean forceResizable = Settings.Global.getInt(context.getContentResolver(),
DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
mSupportsPictureInPicture = forceResizable || context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_PICTURE_IN_PICTURE);
}
通过PhoneWindow构造方法可以发现:PhoneWindow(Context context, Window preservedWindow)是acitivity的主窗口构造方法。在mDecor = (DecorView) preservedWindow.getDecorView(),可以看到getDecor实现的是installDecor();
@Override
public final View getDecorView() {
if (mDecor == null || mForceDecorInstall) {
installDecor();
}
return mDecor;
}
在installDecor()中,
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
...
看下generateDecor(-1),判断是否能使用DecorContext:能则先获取applicationContext;系统进程没有application context时,在这种情况下需要直接使用当前拥有的context(/1),否则我们想要application context时,DecorView无法附着于activity上。application context不为空,new一个DecorContext(/2)。返回DecorView.
protected DecorView generateDecor(int featureId) {
// 系统进程没有application context时,在这种情况下需要直接使用当前拥有的context,不然我们想要application context时,DecorView无法附着于activity上。
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
/1
context = getContext();
} else {
/2
context = new DecorContext(applicationContext, getContext().getResources());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
return new DecorView(context, featureId, this, getAttributes());
}
继续向下看,mContentParent = generateLayout(mDecor);
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
....
</code>
查看 generateLayout(mDecor)方法:根据window特点的不同,加载不同的布局,发现所有布局中都有一个id为content的FrameLayout。最终返回的是一个id为content的FrameLayout。
protected ViewGroup generateLayout(DecorView decor) {
....获取并设置窗口参数
// Inflate the window decor.
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;//滑动消失布局
} else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
//dialog,左右2个ICON按钮
if (mIsFloating) {
//悬浮
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_title_icons;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
// System.out.println("Title Icons!");
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
// Special case for a window with only a progress bar (and title).
// XXX Need to have a no-title version of embedded windows.
layoutResource = R.layout.screen_progress;
// System.out.println("Progress!");
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
// Special case for a window with a custom title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_custom_title;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
// If no other features and not embedded, only need a title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = a.getResourceId(
R.styleable.Window_windowActionBarFullscreenDecorLayout,
R.layout.screen_action_bar);
} else {
layoutResource = R.layout.screen_title;
}
// System.out.println("Title!");
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
mDecor.startChanging();
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
return contentParent;
}
再回到setContentView(int layoutResID),看(1.),mLayoutInflater将layoutResID布局加载到id为content的FrameLayout中。
setContentView(int layoutResID) {
...
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
//1.
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
至此,setContentView(@LayoutRes int layoutResID)结束了。整个流程为:获取PhoneWindow–>安装DecorView–>调用mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);获取id为content的FrameLayout–>将layoutResID布局资源加载到content中。