View刷新中的疑问
解释View刷新机制之前,我们先看看平时可能遇到的一些疑问:
- 我们都知道Android每隔16.6ms刷新一次屏幕,是指每隔16.6ms调用一次onDraw()?
- 如果当前界面没有任何变化,还会每隔16.6ms刷新一次屏幕吗?
- 我们调用完了view的invalidate()方法或者对界面的一些操作后,屏幕会马上刷新吗?
- 我们说的主线程耗时会导致丢帧,这丢帧到底是怎么发生的?
显示系统基本概念
显示系统分为:CPU、GPU、Display三个部分
- CPU负责计算数据,把计算好的数据交给GPU
- GPU会对图形数据进行渲染,渲染好后放到buffer里存起来
- Display负责把buffer里的数据呈现到屏幕上
对于Android,CPU计算数据就是指的View树的绘制过程,包含每个View的测量、布局、绘制 我们常说的Android每隔16.6ms刷新一次屏幕其实是指:底层以固定的频率将buffer里的屏幕数据显示出来
- 底层以固定频率发出VSync信号,这个固定频率也就是我们说的16.6ms间隔。
- 刷新信号到的时候CPU开始计算下一帧数据。
- 刷新信号到的时候,屏幕切换下一帧画面。
解答疑问
- 我们说的16.6ms刷新一次屏幕其实是指底层会以这个固定频率来切换每一帧画面。
- CPU绘制视图是等刷新信号来的时候才开始计算下一帧数据的,而当这个计算工作完成后,也不会马上显示出来,而是等下个信号来的时候才交由底层将数据显示出来。
遗留疑问:为什么界面不刷新app就接收不到刷新信号?
为什么绘制视图的计算是等屏幕刷新信号来的时候才开始的?
Read The Fucking Source Code
ViewRootImpl
我们知道DecorView是整个ViewTree的最顶层View,是一个ViewGroup。 而DecorView的parent又是ViewRootImpl(具体DecorView和ViewRootImpl是怎么绑定上的可以在Activity的启动中找到,这里就不做详细解释了),所有跟View刷新相关的操作,循环找parent时都会走到ViewRootImpl里来。
我们以invalidate()为例来看看View的刷新机制
子view的invalidate(),最终走到了父布局ViewGroup的invalidateChild()方法
通过一个do while循环查找父布局,最终指向了ViewRootImpl的invalidateChildInParent()方法
最后走到了ViewRootImpl的scheduleTraversals()
小结
View的invalidate()方法,通过一系列条件判断和循环查找父布局的工作,最终走到ViewRootImpl的scheduleTraversals()方法里。 类似,除了invalidate(),requestLayout()、requestFocus()、Animation等等跟View相关的刷新操作,最后也都会走到这个方法里。
scheduleTraversals()
我