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

本网站文章均为原创内容,并可随意转载,但请标明本文链接
如有任何疑问可在文章底部留言。为了防止恶意评论,本博客现已开启留言审核功能。但是博主会在后台第一时间看到您的留言,并会在第一时间对您的留言进行回复!欢迎交流!
本文链接: https://leetcode.jp/setcontentview是如何一步一步被显示出来的?/

此条目发表在Android分类目录。将固定链接加入收藏夹。

发表评论

您的电子邮箱地址不会被公开。