通过Activiyt布局加载流程源码分析(I)和Activiyt布局加载流程源码分析(II)两篇博文,我们知道,首先,Activity的布局内容被加载进入装饰器DecorView中,然后WindowManager将DecorView添加到PhoneWindow中,也即Window中,最后ViewRootImpl对DecorView进行绘制操作,将其内容显示到手机上。但前两篇博文中,对于DecorView的绘制原理,没有作详细说明,所以本篇博文重在梳理这部分逻辑。
在开始分析之前,我们需要了解一些概念,如:
- DecorView:是PhoneWindow中的一个内部类,也是Window的顶级View,主要负责装载各种View和Activity布局。
- ViewRootImpl:是View的绘制的辅助类,所有View的绘制都离不开ViewRootImpl。
- Choreographer:是”舞蹈指挥”者,控制同步处理输入(Input)、动画(Animation)、绘制(Draw)三个UI操作。
- DisplayEventReceiver:是一个抽象类,主要是接收显示绘制帧的垂直脉冲vsync,从而开始绘制帧。
- FrameDisplayEventReceiver: Choreographer的内部类,也是DisplayEventReceiver具体实现类。
在说DecorView的绘制之前,我们先来说说Android的绘制原理,这样方便我们理解后面内容。
一、Android的绘制原理简介
Android系统每隔16ms会发出VSYNC信号重绘我们的界面(Activity)。为什么是16ms, 因为Android设定的刷新率是60FPS(Frame Per Second), 也就是每秒60帧的刷新率, 约合16ms刷新一次。如下图所示:
二、DecorView绘制原理分析
在Activity布局加载流程分析中,我们知道DecorView被添加进入了WindowManager,并且最后ViewRootImpl通过setView()方法开始绘制DecorView,所以下面我们就来看看ViewRootImpl的setView()方法
首先,我们来关注一下注释1,这里主要是对mView进行赋值DecorView,mView是ViewRootImpl的属性变量,这里需要注意一下,因为后面绘制需要用到。我们再来看注释2,ViewRootImpl的requestLayout()方法,我们具体来看看其方法逻辑
这里我们直接来看核心方法scheduleTraversals()
这里我们需要特别关注mChoreographer,即Choreographer类,从字面意思来说是“舞蹈指挥”者,是Android绘制原理的核心类,控制Android显示帧的绘制。关于Choreographer类,这里不做过多的分析,想了解其原理的同学,可以看看博文Android Choreographer 源码分析。
由Android绘制原理,我们知道每隔16ms,Android系统就会发出垂直信号VSYNC脉冲重绘我们的界面,而Choreographer中postCallback()方法主要功能就是向系统添加回调并加入绘制帧,从而实现View的绘制。这里我们来看看添加的回调mTraversalRunnable
我们继续来看doTraversal()方法
我们继续分析方法performTraversals()
此方法,可以说是Android系统绘制的核心方法。View绘制原理的三大流程:View的测量onMeasure -> View的布局onLayout -> View的绘制onDraw,都在此方法中提现出来了。下面我们一一来看一下相关方法,首先我们来看一下performMeasure()方法
根据上面的分析,我们知道mView就是DecorView,所以这里就是调用DecorView的measure()方法。由Activity布局加载流程源码分析(I)博文,我们知道DecorView是继承至FrameLayout,而FrameLayout又继承至ViewGroup,ViewGroup又继承至View,所以这里的measure()方法就是调用View中的measure()方法,具体怎么调用,这里不细说了,想了解的同学可以看看这篇博文View的绘制原理。下面让我们来看看performLayout()方法
这里逻辑与测量measure类似,也就是调用DecorView的layout方法,具体View的布局控制细节略。我们再来看看performDraw()方法
我们继续来看看draw()方法
这里的绘制方法涉及到两种绘制方式,分别为Hardware渲染(硬件加速)和Software渲染,关于选择那种绘制方式,这里还需要回溯到ViewRootImpl的setView()方法,我们再来看看此方法
我们知道DecorView是实现了RootViewSurfaceTaker接口的,所以当View为DecorView时,就不会开启硬件加速,不会走Hardware渲染,而其他的View会选择Hardware渲染。因为WindowManager添加的View可能使DecorView,也可能不是DecorView,也可能是一般的View。我们来看看enableHardwareAcceleration()方法
这方法主要是对mAttachInfo.mHardwareRenderer进行赋值,从而在performDraw()方法中可以执行绘制。下面我们来看看上面的绘制方式1,Hardware渲染(硬件加速),由上知主要是通过attachInfo.mHardwareRenderer.draw()绘制,所以我们来看看HardwareRenderer中的draw()方法
当displayList为空的时候,也就会调用 view.draw(canvas)方法,即DeocorView的draw()方法。关于DisplayList这里也不细说,它主要是View中的显示列表记录,具体作用这里不作详述了。我们再来看看第二种绘制方式SoftWare渲染,drawSoftware()方法
这里发现,最后也还是调用DecorView的draw方法,具体流程也与measure和layout类似。可以说两种绘制方式最后也还是调用了View的draw方法,可以说是殊途同归。
到这里我们就把添加的回调绘制帧mTraversalRunnable这个说完了。上面说到,Choreographer通过postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null)方法向系统添加回调并加入绘制帧,然后Android系统通过16ms间隔脉冲实现帧的绘制,从而才将布局内容显示到手机上。
说到这里,DecorView的绘制流程我们就说完了。
注:源码采用android-4.1.1_r1版本,建议下载源码然后自己走一遍流程,这样更能加深理解。