显示子系统之:Choreographer

目录

1. 关键成员变量和方法

1.1 关键成员变量

1.1.1 CallBack Type及其演进历程

1.1.2 mCallbackQueues

1.1.3 mDisplayEventReceiver

1.2 关键函数

1.2.1 构造函数

1.2.2 doFrame

1.2.3 doCallbacks

2. 关键流程

2.1 CALLBACK_INPUT相关流程

2.2 CALLBACK_TRAVERSAL 

2.3 CALLBACK_ANIMATION


google对于这个类功能描述是:choreographer接收定时脉冲(如vsync)然后安排应用的绘制工作

* <p>
 * The choreographer receives timing pulses (such as vertical synchronization)
 * from the display subsystem then schedules work to occur as part of rendering
 * the next display frame.
 * </p><p>

1. 关键成员变量和方法

1.1 关键成员变量

1.1.1 CallBack Type及其演进历程

我们来看一下CallBack Type的发展历程,2014年之前也就有CALLBACK_INPUT、CALLBACK_ANIMATION,CALLBACK_TRAVERSAL,2015年4月左右加了CALLBACK_COMMIT,2018年12月加入了CALLBACK_INSETS_ANIMATION

对于CALLBACK_INPUT、CALLBACK_ANIMATION,CALLBACK_TRAVERSAL比较好理解同时在systrace上我们也经常见到:

    //处理input
    public static final int CALLBACK_INPUT = 0;
    //处理animation
    public static final int CALLBACK_ANIMATION = 1;
    //处理insets animaition
    public static final int CALLBACK_INSETS_ANIMATION = 2;
    //处理视图绘制,遍历,执行 measure、layout、draw
    public static final int CALLBACK_TRAVERSAL = 3;
    //遍历完成的提交操作,用来修正动画启动时间
    public static final int CALLBACK_COMMIT = 4;

对于CALLBACK_COMMIT 和 CALLBACK_INSETS_ANIMATION 平时就很少碰到,我们先来看一下CALLBACK_COMMIT提交commit信息

commit c42b28dda45347b05826dc3e04f5605a60867a63
Author: Jeff Brown <jeffbrown@google.com>
Date:   Mon Apr 6 19:49:02 2015 -0700

    Fix animation start jank due to expensive layout operations.

    The Choreographer carefully schedules animation updates to occur
    after input but before traversals occur.  This ensures that the
    effects of animations are perceived immediately in the next frame.
    The start time of animation is usually set the moment the animator
    first runs.  The start time serves as a reference for timing the
    remainder of the animation.

    Setting the start time during the animation callback works well except
    when traversals take a long time to complete.  In that case, we may
    end up drawing the initial frame of the animation then skipping several
    following frames (because a lot of time has already passed since the
    animation start time was set), effectively shortening the duration
    of the animation.

    To resolve this issue, we introduce a new COMMIT phase within the
    Choreographer.  The COMMIT callback runs after traversals complete
    and may provide an updated frame time that more accurately reflects
    the time when the frame finished drawing.

    In the case where an animation is just starting, we note the fact
    that its initial start time has not yet been committed (the user
    hasn't actually seen anything on screen yet).  Then, during the
    COMMIT phase, we adjust the animation start time to better reflect
    the time when the animation's first frame was drawn, effectively
    causing the animation actually start after the expensive traversal
    operations occurred such that no frames will be skipped.

    Bug: 17258911
    Change-Id: I279603d01fd4ed1de8f51a77c62f4fec5e9b746a

修复了由于layout操作耗时导致的 animation start 卡顿

Choreograhper执行会在input和traversals之间执行animation的更新这确保了animation效果会在下一帧中立即感知。animation start时间通常由动画工程师设定。开始时间用来作为动画的其余部分计时的参考。 在动画回调期间设置开始时间效果一般很好,遍历需要很长时间才能完成时除外,这种情况,初始帧绘制结束的时候,已经跳过几个帧(因为从 动画开始时间设置已经过去了很多帧的时间),实际动画的部分已经被缩短。 为了解决这个问题,google在Choreograhper中引入了CALLBACK_COMMIT。 CALLBACK_COMMITZ在CALLBACK_TRAVERSAL完成后运行,可能会去提供frame time的更新。 在动画刚刚开始的情况下,我们注意到其初始开始时间尚未提交(用户还没在屏幕上看到任何东西)。然后,在CALLBACK_COMMIT阶段,我们调整动画开始时间,即使有在开始的时候有一个非常耗时的traversal 操作,也不会跳过任何帧

关键修改在doCallBack中:

我们只在当前 frame 渲染时间超过了两个时钟周期且当处于CALLBACK_COMMIT这个阶段去更新当前frame的时间,这样可以确保下一个frame 的提交时间和当前 frame 时间相差为一且不重复,我们从不希望下一帧的开始帧时间最终小于或等于前一帧的提交帧时间,请记住,下一帧很可能现在已经安排好了,所以我们要确保提交时间总是至少落后一帧。

  // Update the frame time if necessary when committing the frame.
            // We only update the frame time if we are more than 2 frames late reaching
            // the commit phase.  This ensures that the frame time which is observed by the
            // callbacks will always increase from one frame to the next and never repeat.
            // We never want the next frame's starting frame time to end up being less than
            // or equal to the previous frame's commit frame time.  Keep in mind that the
            // next frame has most likely already been scheduled by now so we play it
            // safe by ensuring the commit time is always at least one frame behind.
            if (callbackType == Choreographer.CALLBACK_COMMIT) {
                final long jitterNanos = now - frameTimeNanos;
                Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
                if (jitterNanos >= 2 * mFrameIntervalNanos) {
                    final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
                            + mFrameIntervalNanos;
                    if (DEBUG_JANK) {
                        Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
                                + " ms which is more than twice the frame interval of "
                                + (mFrameIntervalNanos * 0.000001f) + " ms!  "
               
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值