作者:花海blog
前言
针对Android UI不流畅的问题,Google提出了Project Butter对Android的显示系统进行了重构。 这次重构的三个关键点
- VSynch 垂直同步
- Triple Buffer 三重缓存
- Choreographer 编舞者
这篇文章我们主要聊一聊Choregrapher,后续的我们写关于其他。
choreographer
界面的显示大体会经过CPU的计算-> GPU 合成栅格化->显示设备显示。我们知道Android设备的刷新频率一般都是60HZ也就是一秒60次,如果一次绘制在约16毫喵内完成时没有问题的。但是一旦出现不协调的地方就会出问题如下图
- 第一个周期内cpu计算、GPU操作、显示设备显示没有问题
- 第二周期内,显示上一个周期绘制准备好的图像,没有问题。CPU计算是在周期将要结束的时候才开始计算
- 第三个周期,由于进入第第二个周期的时候CPU动手计算晚点了导致后续,进入第三个周期的时候本应该显示的图像没有准备好,导致整个第三个个周期内还是显示上一个周期的图像,这样看上去会卡,掉帧!google工程师们管整个叫Jank延误军机。

这事不小啊,怎么解决呢?垂直同步 简单的说,就是让CPU计算别没有计划没有规律而是在每个周期开始的时候开始计算,紧接着这样就有条不紊的有序进行了(如下图)。这个在android4.1及以后的版本中加入了Choreographer这个类,让我们扒开看看他是怎么实现的。

一、入口
1.1 postCallbackDelayedInternal
ViewRoot的 doTravle()方法中有这样一行代码
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
它的意思就是对整个View树发起测量布局绘制操作。关于ViewRootImpl的更多内容这里就不多介绍了。
以下方法
- public void postCallback(…) ;
- public void postCallbackDelayed(…);
- public void postFrameCallback(FrameCallback callback);
- public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis)
最终都会调用 postCallbackDelayedInternal();,那么我们就看看这个方法的功能。
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();//获取当前时间
final long dueTime = now + delayMillis;//到期时间
//将执行动作放在mCallback数组中
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
//如果已经到期就注册请求垂直同步信号
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
//如果还没有到期,使用handler在发送一个延时消息。这个延时消息会在到期的时候执行。
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
1.2 FrameHandler
上一小节,如果已经到期就直接执行scheduleFrameLocked()方法,如果没有执行就使用mHandler(FrameHandler类型)发送一个what值为MSG_DO_SCHEDULE_CALLBACK的Message。到期后怎么执行的呢。这要看FrameHandler怎么处理的。
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_FRAME:
doFrame(System.nanoTime(), 0);
break;
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
case MSG_DO_SCHEDULE_CALLBACK:
//postCallbackDelayedInternal()方法中当未到期的时候发送过来的
doScheduleCallback(msg.arg1);
break;

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



