直接通过源码来进行分析:
涉及相关类:Activity, PhoneWindow(extends Window), DecorView(extends FrameLayout);
1.创建顶层布局容器DecorView;
2.在顶层布局中加载基础布局viewGroup;
3.将ContentView添加到基础布局中的FrameLayout中;
先看流程:
Activity: setContentView() ->getWindow().setContentView(layoutResID)
PhoneWindow:setContentView() -> installDecor()
(->把布局添加到根布局中)
->generateDecor()创建DecorView容器
->generateLayout(mDecor):加载样式和不同的根布局,添加到DecorView中;
->初始化了布局容器contentParent;
PhoneWindo.java
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();//这里是加载DecorView 和初始化 mContentParent 重点
} 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中,完成,view的添加;
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1);//这里是初始化 DecorView 这是一个FrameLayout
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);//这里是重点,完成主题、布局样式等,并初始化mContentParent
...
...
}
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
TypedArray a = getWindowStyle();
...//主要是设置主题样式
...
// Inflate the window decor.
int layoutResource;//根据features 获取一个layout
int features = getLocalFeatures();
...
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);//把layout作为decorview的根布局
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
...
return contentParent;
}
在获取到contentParent后,在PhoneWindow中的setContentViw中 mLayoutInflater.inflate(layoutResID, mContentParent);完成了自己的资源添加到了窗口;
网友评论