setContentView是如何一步一步被显示出来的?

通常我们在onCreate中会调用setContentView方法,如下:


640?wx_fmt=png

image.png


setContentView里面优势怎么样执行的呢,进去看看,如下:


640?wx_fmt=png

image.png

跳转到getWindow().setContentView(layoutResID)如下:


640?wx_fmt=png

image.png

Window类型的继承树如下:


640?wx_fmt=png

image.png


Window只有一个实现类PhoneWindow,那也就是说getWindow().setContentView(layoutResID)调用的是PhoneWindow的setContentView,如下:


640?wx_fmt=png

image.png


先来看看上图中标记A的地方,调用installDecor方法,看名字的意思是创建decor的意思,而这个decor如果你熟悉Adroid 视图的层级结构的话,会一下子就理解,这里我给一张图帮助你理解:

640?wx_fmt=png

无标题.png

DecorView实际上是作为Activity上的视图的最顶层View,而我们自己的布局则是上图粉色区域,外面还包含着一层,称之为contentParent,从名字上看也是取得很贴切,嗯还是进入源码看看一下是不是上图描述的那样,如下:


640?wx_fmt=png

image.png


genereteDecor方法调用如下:


640?wx_fmt=png

image.png


generateLayout方法如下:

640?wx_fmt=png

image.png

至此可以看到最顶层布局,以及我们自己的布局的复布局都已创建好了,回到上图标记B 的地方,可以看到调用了    mLayoutInflater.inflate(layoutResID, mContentParent);
这个layoutResID就是我们自己的布局的id,调用完这一句我们自己的布局也被创建出来了,到这里你应该会有一个疑问:Activity的整个View视图都被创建好了,那么接下来应该是要绘制这个视图才对,我第一次看这个源码的时候也是有这个疑问,同时还犯了一个错误,我试图在mLayoutInflater.inflate(layoutResID, mContentParent);这句之后查找开启绘制试图的代码,查看源码我根本就找不到,一下子就懵逼了,如下:


640?wx_fmt=png

image.png

其实这是我忽略了一个事实,这个setCotentView 是在onCreate被调用的这个时候View是不能见,真正能见的是在onResum时候,对哦,恍然大悟!!如果你有阅读之前的那篇Activity生命周期回调是如何被回调的?应该会知道onResume何时开始被调用,如下:

640?wx_fmt=png

image.png


640?wx_fmt=png

image.png


上图这个方法是在ActivityThread类中的,看到标记E的地方,是开始Activity的onResume的调用,进去看看,如下:


640?wx_fmt=png

image.png

进入wm.addView看看如何,调用的是它的实现类WindowManagerImpl的addView如下:


640?wx_fmt=png

image.png


跳转如下:


640?wx_fmt=png

image.png


ViewRootImpl调用setView如下:

640?wx_fmt=png

image.png


setView方法里面调用了requestLayout,这个方法名让我们看到了是在做绘制View视图的苗头,进去看看是不是如此:


640?wx_fmt=png

image.png


640?wx_fmt=png

image.png


mTraversalRunnable对象的类相貌如下:

640?wx_fmt=png

image.png


可以看到在run方法里面调用doTraversal,如下:


640?wx_fmt=png

image.png

performTraversals方法的代码是在是太长了,这里我不截图,这个方法里面调用了三个关键的方法:performMeasure方法开启视图的测量流程,performLayout方法开启了视图的布局流程,performDraw开启了视图的绘制流程,这3个方面的具体细节我准备在其他篇章来介绍,这3个流程走完,视图就会被真正的绘制完成。到此setContentView的工作是如何一步一步被现实的,你是否有一个比较深的理解了,回顾一下前面讲的东西,可以总结如下:

1.setContentView只是将Activity的整个View视图创建好,放在一边而已,而执行创建View视图的则是PhoneWindow

2.在Activity在准备转换成Resume状态的之际,即调用handleResumeActivity,会将最顶层View——DecorView兜兜转转传到WindowManagerGlobal 手中

3.DecorView在WindowManagerGlobal 手中,首先先添加进View数组方便管理同时会为这个DecorView也可以说是这个视图创建一个ViewRootImpl

4.ViewRootImpl 将调用setView 将DecorView传入,开启绘制之旅

5.所以从前四步来看,真正导致Activity整个视图会被绘制的罪魁祸首是WindowManagerGlobal



作者:钟离四郎
链接:https://www.jianshu.com/p/d36398c9d498
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

                        喜欢 就关注吧,欢迎投稿!

640?wx_fmt=jpeg



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值