setContentView()绘制流程源码分析:
先从Activity 中的onCreate()中开始寻找如图:
然后点开发现在Activity中调用了其中的setContentView如图:
再往下走会找到一个Window 抽象方法,
而在这里这个抽象方法的头部写着:
标识着这个抽象的方法的唯一的实现类就是这个PhoneWindow.也就是说上边的Activity中调用的SetContentView 会最终调用到这PhoneWindow中
在这个PhoneWindow当中主要做了两件事情:
1:installDecor() 加载布局容器
2:加载解析自己写的布局。
在这里需要对上边的内容进行简单的归纳:在Activity中是用继承子Window的PhoneWindow来实现SetContentView的 而其中它实现了重要的两步,加载了系统基础布局,然后解析了自己写的布局。
这是DecorView默认的一个渲染,然后我们自己的布局都是渲染到她的FrameLayout上的
那么在这里我们现在能够明白,installDector其实实际上是在初始化两个视图容器,然后加载系统的R资源及特征,产生了一个基本布局
那么接着回到之前我们关注的另外一个方法mLayoutInflater.inflate(layoutResID, mContentParent);
这个方法就比较好理解了,
这这段注释上面我们就可以得到一个信息
//Inflate a new view hierarchy from the specified xml resource.(从指定的视图当中获取试图的层次结构,意思就是,现在在加载自己的资源)
而具体流程就不贴代码了给各位上一张图
这个就是解析布局的步骤。
在解析View渲染之前在说一个重要的方法:WindowManager
首先要看的就是最顶层的一个接口:这个接口中声明了三个方法
然后下边又有一个继承自接口的接口:
最后是一个他的实现类:在ActivityResumeLaunchActivity中也就是这个大哥来管理布局容器和布局属性的。而在这个来中的第一行代码中有个WindowManagerGlobal对象,而且还是通过单例的模式来获取这个对象的,这个类中是干啥 的呢点进去看一下:
在这个类中可以看到有获取单例的方式,以及获取一个ServiceManager服务的Binder对象,
还有下边获取RootView() WindowsView()的方法,以及下边最最最最重要的addView()方法,在上边ActivityThread中的addView()最终就是调用到这里的addView().下边重点研究一下这个addView()方法的具体实现。
在这个addView中最重要的就是下边三行代码:
把view root wparams三个对象分别放到对应的集合当中,然后通过ViewRootImpl对象中setView()方法把三个进行关联...
进入addView之后我们发现了一段这样的代码,他将视图,和参数还有我们的一个ViewRoot对象都用了容器去装在了起来,那么在此处我们可以得出,是将所有的相关对象保存起来
mViews保存的是View对象,DecorView
mRoots保存和顶层View关联的ViewRootImpl对象
mParams保存的是创建顶层View的layout参数。
而WindowManagerGlobal类也负责和WMS通信
而在此时,有一句关键代码root.setView,这里是将我们的参数,和视图同时交给了ViewRoot,那么这个时候我们来看下ViewRoot当中的setView干了什么?继续往下找,这次需要在ViewRootImpl中来找了,
然后在这个addVIew()方法中有个最重要的方法就是requestLayout() 其余的都是垃圾。可以不用看同时这行代码上边有个最长的注释,也就说明了这行代码的重要i行了。继续往下找~
在这里里边有三个代码,这里有两行重要的代码:
1:checkThread();看到这个throw 的Exception 熟悉吧,这不就是程序中子线程更新UI报的异常?开发人员应该都遇到过这个异常吧,在渲染布局前检查了一下当前的线程是不是主线程,如果不是主线程那么不允许更新UI...明了了吧.........
2:然后继续往下看下边的一行代码:
其实回调中后调用就是doTraversal() 方法,而这个方法 中调用到了performTraversals() 方法。看到这个方法就表示着UI可以开始渲染了......开心吧,上边这麽多行代码就是到这才开始的绘制渲染流程....
不截图了太麻烦了简单总结上边的流程:
看这麽多行代码最后如果都记不住,就记住这个方法就行了....
performTraversals()
View绘制从ViewRoot的performTraversals方法开始,经过measure、layout、draw三个过程,然后将View绘制出来
measure方法用于测量View的宽高
layout方法用于确定View在父容器中的位置
draw方法负责将View绘制在屏幕上
如下是performTraversals的流程图: