熟悉完 View
的基础,了解完其分发流程,事件分发的传递规则。我们需要深入理解 View
的工作流程,包括绘制原理以及三大方法的流程,洞悉其原理和实现。
页面绘制流程
页面如何展示到屏幕
当我们在 Activity
的 onCreate
() 中调用 setContentView()
来设置根布局的时候,这个方法是一步步新建了一个 PhoneWindow
,再然后 PhoneWindow
就是以 DecorView
作为一个根部的 View
来添加内容。那么 DecorView
是如何被加载到 Window
的呢?
事实上,Activity
在执行了 onCreate()
的相关方法之后,会跳转到执行 onResume()
的相关方法,DecorView
就是在这个阶段被加载到 Window
的。
页面绘制的总体流程如上图
最左侧的序列,最后完成的是 addView()
,所添加的 View
其实是 DecorView
。在管理着 Activity
生命周期的 onResume()
时期的 handleResumeActivity()
方法中,该方法在成功的发起了 onResume()
方法之后,就会开启这个序列。这也是为什么在 onResume()
执行的时期,Activity
才会可见,因为这个时候才会把顶层的 DecorView
添加进去。
接着是 ViewRootImpl
这个方法的序列。在 addView()
里面,ViewRootImpl
会调用 setView()
来设置 DecorView
,和调用 requesLayout()
来请求开始绘制流程。这时候并非一请求就会开始绘制了,何时开始绘制是由下一个序列的 Choregrapher
所决定的。
到达 Choregrapher(舞蹈编导)
管理的这个序列,从名字我们就可以了解到这是一个管理的方法。它的主要作用就是管理什么时候执行绘制,在其调用了回调之后,页面才会开始执行绘制,到最后的调用三大方法。
在最后的一个序列中,调用 WindowManagerService
方法之后,addVindow
() 才会被调用来展示页面到屏幕。
页面多久绘制一次
我们在 Activity 中设置了布局文件之后,还会有很多页面的改动,动画的执行。那么是一执行到这些改动,页面就会立刻响应变化吗?有多个改动的话,是一个个排队执行改动吗?
其实是和上文提到的一样,这些改动是由 Choregrapher
来管理的。那么它如何管理的呢。这涉及到一个帧率的概念,譬如 60 帧就是指屏幕每秒会刷新60次。而页面的改动,统一就是在每一帧刷新的时候进行更新改动的。
我们可以查看上图,在每个时间片内,蓝色阶段是 CPU 执行 Measure
Layout
Draw
这些个方法,绿色阶段则是 GPU 对这些的合成。然后到达了 VSync 这个时间的时候,就是屏幕刷新来展示这些新的或者更改后的页面了。那么有没有 CPU + GPU 执行的时间超时的情况呢,当出现这个情况的时候,就是出现了丢帧现象,说明我们需要对业务进行优化了。
附:页面执行绘制的渲染流程
UI渲染流程
渲染流程