一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第24天,点击查看活动详情。
3.DecorView
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
......
//通过Inflater解析XML布局文件,得到一个View对象
//root就是DecorView中添加的layoutResource,即R.layout.screen_simple.xml
final View root = inflater.inflate(layoutResource, null);
//通过addView把布局文件添加到DecorView中
if (mDecorCaptionView != null) {
if (mDecorCaptionView.getParent() == null) {
addView(mDecorCaptionView,
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mDecorCaptionView.addView(root,
new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
// Put it below the color views.
addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mContentRoot = (ViewGroup) root;
initializeElevation();
}
}
前面说到的,执行generateLayout(DecorView decor)主要做了以下两个工作:
1.创建对应layoutResource = R.layout.screen_simple的布局,然后将布局加载到DecorView中;
2.从加载的布局文件中找到R.id.content控件,返回contentParent,供activity显示界面;
再回到PhoneWindow.java中的setContentView()方法:
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//初始化DecorView
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();
}
mContentParentExplicitlySet = true;
}
分析:执行mLayoutInflater.inflate(layoutResID, mContentParent)解析布局并加载,将setContentView()传进来的xml布局解析加载到mContentParent上,mContentParent是R.layout.screen_simple.xml中的FrameLayout,然后将activity中setContentView()传进来的xml布局解析加载到mContentParent上。
4.简单总结
1、在PhoneWindow中创建顶层的DecorView;
2、在DecorView中会根据主题的不同加载一个不同的布局;
3、从加载到DecorView中的布局中找到contentParent(即FrameLayout);
4、把Activity中的布局解析并添加到contentParent中;
引用大佬画的图,比较清晰,setContentView()涉及到的布局结构及布局文件如下:
5.setContentView整个执行流程
二.View的显示
当执行到handleResumeActivity时,Activity的onResume()方法被调用,然后WindowManager会将DecorView设置给ViewRootImpl,这样DecorView就被加载到Window中了,此时界面还没有显示出来,还需要经过View的measure,layout和draw方法,才能完成View的工作流程。
View的绘制是由ViewRootImpl来负责的,每一个DecorView都有一个与之关联的ViewRootImpl,这种关联关系是由WindowManager维护的,将DecorView和ViewRootImpl关联(通过ViewRootImpl的setView方法)之后,ViewRootImpl的requestLayout会被调用以完成初步布局,通过scheduleTraversals方法向主线程发送消息请求遍历,最终调用ViewRootImpl的performTraversals方法,这个方法会执行View的measure,layout 和draw流程。