setContentView源码分析

ViewRoot 继承自framelayout, 根布局
Window
DecorView

 public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);//实际上是getWindow()在调用,

    initWindowDecorActionBar();//设置ActionBar(不包含状态栏)
}

 public Window getWindow() {
    return mWindow;
}

// Window类的注释代码only existing implementation is PhoneWindow
 public abstract class Window {//唯一的实现类是PhoneWindow
}

PhoneWindow的setContentView核心源码

  if (mContentParent == null) {//mContentParent是viewgroup
      installDecor();//初始化Decor
  } 
//设置我们的布局填充到mContentParent
mLayoutInflater.inflate(layoutResID, mContentParent);

这段代码说明了,实际上我们的布局文件之上,还有一个父容器viewgroup

private void installDecor() {

   if (mDecor == null) {
       mDecor = generateDecor(-1);//创建一个DecorView
       //设置的属性和动画效果直接忽略
   else {
       mDecor.setWindow(this);//DecorView设置一个window
   }
   if (mContentParent == null) {
       mContentParent = generateLayout(mDecor);
     //如果viewgroup为空,则生成一个layout

generateDecor源码分析

protected DecorView generateDecor(int featureId) {
    //内部就是new了一个DecorView。
    return new DecorView(context, featureId, this, getAttributes());
}

generateLayout()源码分析

generateLayout内部实际上就是在setFlags和setLayout和style和requestFeature()和动画一系列的操作最终就是在创建一个DecorView。同时,也印证了,在设置getWindow.requestFeature时,为什么要设置在setContentView()之前,因为这些在之前就已经设置了。最后是会根据不同的状态去加载不同的布局

//最后会加载layoutResource
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

onResourcesLoaded内部实际上就是把layoutResource填充进来

void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
      final View root = inflater.inflate(layoutResource, null);
}

创建完父容器之后,再去填充我们自己的布局,底层是用的xml解析,解析过程(略)。

也就是说,setContentView()实际上就是两步
1.加载父容器(包括各种style和各类资源等),
2.加载自身布局

但是这里仅仅只是加载,正如我们最初在学activity生命周期时,很明确的说明,oncreate()只是在准备阶段,加载资源文件,也就是说,没有将view添加到window。因为oncrete中setContentView()仅仅只是资源准备阶段,只有当ActivityThread执行onReLauchActivity时,也就是onResume()方法时,才会将view添加到window中

下一篇,将会讲解,DecorView是如何添加到窗口window的源码分析

igding wechat
2018 依计行事 持续精进
坚持原创技术分享,您的支持将鼓励我继续创作!