Android 怎么就不卡了呢之Choreographer

作者:花海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;
           
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值