哈哈哈,终于支持markdown啦
每过16.6ms都会回调一次View的onDraw方法吗?
不是的,这个频率,说的是系统发出屏幕刷新信号频率(但我也不太确定是不是真的16.6ms(在源码里没看到过)),但是在onDraw中收到回调的时机,是不确定的(各种原因,如代码写法、设备性能等)。
那它的刷新机制是怎样的呢?
屏幕刷新大致流程:
View调用invalidate方法;
ViewRootImpl会把doTraversal任务(处理View的测量、布局、绘制),post到Choreographer中(在系统下一次发出同步信号的时候,这个doTraversal任务会被执行);
Choreographer会借助DisplayEventReceiver的scheduleVsync方法,在native层(IDisplayEventConnection.cpp)通过Binder(跨进程)发出一个REQUEST_NEXT_VSYNC的Tag(发去了哪里不知道,我找不到那个类);
在DisplayEventDispatcher.cpp中,会看到一个handleEvent方法(可以猜测,系统在下一次发出屏幕刷新信号时,(间接或直接)回调的就是这个方法),它里面会调用android_view_DisplayEventReceiver.cpp中的dispatchVsync方法,这个方法最终去了哪里呢?
回到java层,在DisplayEventReceiver中会看到一个同名同签名的dispatchVsync方法,并且上面有注释写着:Called from native code. (可以知道,这个方法是在native层被调用的),它里面会调用onVsync方法,
而onVsync方法在Choreographer中内部类的实现,最终是会调用doFrame方法的,这个doFrame方法,里面会把刚刚在ViewRootImpl中post到Choreographer里的doTraversal任务(处理View的测量、布局、绘制)执行!!。
以上提到的native层代码,分别(按顺序)在以下链接中能看到:
这个机制在版本迭代中有何变化?
刚刚分别试了下手头上的6.0和9.0系统的测试机,
在一个自定义View中的onDraw方法不断invalidate和打印被回调的时间:
private long lastTime;
@Override
public void onDraw(Canvas canvas) {
LogUtil.print(SystemClock.uptimeMillis() - lastTime);
lastTime = SystemClock.uptimeMillis();
invalidate();
}
发现在6.0的手机是上这样的(随机截取20条log):
onDraw: 14
onDraw: 0
onDraw: 13
onDraw: 0
onDraw: 14
onDraw: 1
onDraw: 14
onDraw: 1
onDraw: 13
onDraw: 0
onDraw: 14
onDraw: 1
onDraw: 14
onDraw: 1
onDraw: 13
onDraw: 1
onDraw: 10
onDraw: 1
onDraw: 12
onDraw: 1
而9.0系统的手机是这样的(随机截取20条log):
onDraw: 15
onDraw: 15
onDraw: 15
onDraw: 15
onDraw: 15
onDraw: 15
onDraw: 15
onDraw: 15
onDraw: 16
onDraw: 15
onDraw: 15
onDraw: 16
onDraw: 15
onDraw: 15
onDraw: 15
onDraw: 15
onDraw: 15
onDraw: 14
onDraw: 15
onDraw: 15
可以看到,在6.0系统上,好像有个缓存机制,不断地invalidate的话,每两次中有一次是<=1ms就回调了,可以猜想这一次没有等待系统的屏幕刷新信号就直接回调了onDraw方法。
而9.0系统则比较稳定,onDraw方法每一次被回调都间隔了15ms左右.