我是靠谱客的博主 失眠羽毛,最近开发中收集的这篇文章主要介绍显示子系统之:Choreographer1. 关键成员变量和方法2. 关键流程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

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!  "
                                + "Setting frame time to " + (lastFrameOffset * 0.000001f)
                                + " ms in the past.");
                        mDebugPrintNextFrameTimeDelta = true;
                    }
                    frameTimeNanos = now - lastFrameOffset;
                    mLastFrameTimeNanos = frameTimeNanos;
                }
            }
        }

 看着上面的各种注释,估计也不一定可以看明白,其实它主要在优化ValueAnimator的动画体验

以上图曲线为例,在不卡顿的情况,正常会按照如下坐标集合进行绘制

{(t,x1,y1)(t+16,x2,y2)(t+32,x3,y3)(t+48,x4,y4)(t+64,x5,y5)......}

如果,在动画开始的时候,第一帧就绘制了48ms,那么第二帧开始绘制第帧时间应该是t+48,如果不做调整那么,绘制的点应该是

{(t,x1,y1)(t+48,x4,y4)(t+64,x5,y5)......}

也就意味着掉了2帧:(t+16,x2,y2)(t+32,x3,y3),

但是如果我们修改动画,

令T=t+32,

那么绘制的点坐标集合就是:

{(T,x1,y1)(T+16,x2,y2)(T+32,x3,y3)(T+48,x4,y4)(T+64,x5,y5)......}

这样我们这样即使,第一帧卡顿了2帧,动画曲线还是还是连续的不会出现掉帧的情况

从 CALLBACK_INSETS_ANIMATION提交的commit信息来看,主要是为了适配InsetsAnimation加,这里没有去进一步的看

从 CALLBACK_INSETS_ANIMATION提交的commit信息来看,主要是为了适配InsetsAnimation加,这里没有去进一步的看

commit 02a741f7a9de104979a81f0e84bfc9bd80f1dafa
Author: Jorim Jaggi <jjaggi@google.com>
Date:   Wed Dec 12 17:40:19 2018 -0800

    A brave new world for window insets (11/n)

    Implement animation listeners

    Test: CTS will be added in the future
    Bug: 118118435
    Change-Id: If6c1153da007b80859485ecbcdc1610d1d82373e

1.1.2 mCallbackQueues

mCallbackQueues是一个长度为5的数组,数组元素为CallbackQueue(一个链表)

 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
       public void addCallbackLocked(long dueTime, Object action, Object token) {
            CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);
            CallbackRecord entry = mHead;
            if (entry == null) {
                mHead = callback;
                return;
            }
            if (dueTime < entry.dueTime) {
                callback.next = entry;
                mHead = callback;
                return;
            }
            while (entry.next != null) {
                if (dueTime < entry.next.dueTime) {
                    callback.next = entry.next;
                    break;
                }
                entry = entry.next;
            }
            entry.next = callback;
        }

1.1.3 mDisplayEventReceiver

mDisplayEventReceiver是 FrameDisplayEventReceiver对象, FrameDisplayEventReceiver是DisplayEventReceiver子类,主要是用来接收同步脉冲信号 VSYNC,

HW_VSYNC,唤醒DispSyncThread线程,再到EventThread线程,然后再通过BitTube直接传递到目标进程所对应的目标线程,执行handleEvent方法

(图From:https://blog.csdn.net/sosesoA/article/details/51087639)

(图From:https://blog.csdn.net/sosesoA/article/details/51087639)

FrameDisplayEventReceiver是DisplayEventReceiver子类,在初始化的时候,最终会去监听vysnc消息:

1.FrameDisplayEventReceiver初始化的时候会调用DisplayEventReceiver构造函数

2.通过jni调用nativeIni

3.监听mReceiver的所获取的文件句柄,一旦有数据到来,则回调this(此处NativeDisplayEventReceiver),中所复写LooperCallback对象的 handleEvent

frameworks/base/core/java/android/view/Choreographer.java
 public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
            // 1.FrameDisplayEventReceiver初始化的时候会调用DisplayEventReceiver构造函数
            super(looper, vsyncSource, CONFIG_CHANGED_EVENT_SUPPRESS);
        }
 frameworks/base/core/java/android/view/DisplayEventReceiver.java
   public DisplayEventReceiver(Looper looper, int vsyncSource, int configChanged) {
        if (looper == null) {
            throw new IllegalArgumentException("looper must not be null");
        }

        mMessageQueue = looper.getQueue();
        //2.通过jni调用nativeInit
        mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
                vsyncSource, configChanged);

        mCloseGuard.open("dispose");
    }
frameworks/base/core/jni/android_view_DisplayEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject messageQueueObj, jint vsyncSource, jint configChanged) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
            receiverWeak, messageQueue, vsyncSource, configChanged);
    status_t status = receiver->initialize();
    if (status) {
        String8 message;
        message.appendFormat("Failed to initialize display event receiver.  status=%d", status);
        jniThrowRuntimeException(env, message.string());
        return 0;
    }

    receiver->incStrong(gDisplayEventReceiverClassInfo.clazz); // retain a reference for the object
    return reinterpret_cast<jlong>(receiver.get());
}
frameworks/native/libs/gui/DisplayEventDispatcher.cpp
status_t DisplayEventDispatcher::initialize() {
    status_t result = mReceiver.initCheck();
    if (result) {
        ALOGW("Failed to initialize display event receiver, status=%d", result);
        return result;
    }

    if (mLooper != nullptr) {
        //3. 监听mReceiver的所获取的文件句柄,一旦有数据到来,则回调this(此处NativeDisplayEventReceiver)
        // 中所复写LooperCallback对象的 handleEvent。
    //addFd(int fd, int ident, int events, android::Looper_callbackFunc callback,void* data)
        int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT, this, NULL);
        if (rc < 0) {
            return UNKNOWN_ERROR;
        }
    }

    return OK;
}

int DisplayEventDispatcher::handleEvent(int, int events, void*) {
   ......
    // Drain all pending events, keep the last vsync.
    nsecs_t vsyncTimestamp;
    PhysicalDisplayId vsyncDisplayId;
    uint32_t vsyncCount;
    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
        ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
              ", displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%d",
              this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount);
        mWaitingForVsync = false;
        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
    }

    return 1; // keep the callback
}

1.2 关键函数

1.2.1 构造函数

构造函数主要完成了以下工作:

1. hanlder和looper的初始化

2. 创建VSYNC信号的接收者

3. mLastFrameTimeNanos变量的初始化,用来保存上一帧的绘制时间,把looper和vsyncSource传递给它,这里的vsyncSource就是VSYNC_SOURCE_APP,由注释我们可以知道,这个值是需要和ISurfaceComposer.h,中eVsyncSourceApp这个值保持同步的,也就一样大

4. 没有一帧所需时间的初始化,这个依据屏幕刷新率的不同而不同,60Hz:16.6ms,90Hz:11.1ms,120Hz: 8.3ms

5. 创建一个队列数组,用来保存不同类型的CallBack

6.可以选择设置一个更低的帧率,比如目前屏幕刷新率是120Hz,但是你希望得到一个更低帧率比如60,你就可以设置这个值为2

 private Choreographer(Looper looper, int vsyncSource) {
        // 1. hanlder和looper的初始化
        mLooper = looper;
        mHandler = new FrameHandler(looper);
        //2. 创建VSYNC信号的接收者
        mDisplayEventReceiver = USE_VSYNC
                ? new FrameDisplayEventReceiver(looper, vsyncSource)
                : null;
        //3.mLastFrameTimeNanos变量的初始化,用来保存上一帧的绘制时间                                                                        
        mLastFrameTimeNanos = Long.MIN_VALUE;
        
        //4.没有一帧所需时间的初始化,这个依据屏幕刷新率的不同而不同 
        // 60Hz:16.6ms,90Hz:11.1ms,120Hz: 8.3ms               
        mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
        
         //5. 创建一个队列数组,用来保存不同类型的CallBack                
        mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
        for (int i = 0; i <= CALLBACK_LAST; i++) {
            mCallbackQueues[i] = new CallbackQueue();
        }
        // b/68769804: For low FPS experiments.
        //6.可以选择设置一个更低的帧率,比如目前屏幕刷新率是120Hz,但是你希望得到一个更低帧率比如60,你就可以设置这个值为2
        setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
    }
    
      // Thread local storage for the choreographer.
    private static final ThreadLocal<Choreographer> sThreadInstance =
            new ThreadLocal<Choreographer>() {
        @Override
        protected Choreographer initialValue() {
            Looper looper = Looper.myLooper();
            if (looper == null) {
                throw new IllegalStateException("The current thread must have a looper!");
            }
            Choreographer choreographer = new Choreographer(looper, c);
            if (looper == Looper.getMainLooper()) {
                mMainInstance = choreographer;
            }
            return choreographer;
        }
    };  
android-11.0.0_r21/xref/frameworks/base/core/java/android/view/DisplayEventReceiver.java
  /**
     * When retrieving vsync events, this specifies that the vsync event should happen at the normal
     * vsync-app tick.
     * <p>
     * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h
     */
    public static final int VSYNC_SOURCE_APP = 0;  
frameworks/native/libs/gui/include/gui/ISurfaceComposer.h
  enum VsyncSource {
        eVsyncSourceApp = 0,
        eVsyncSourceSurfaceFlinger = 1
    };

1.2.2 doFrame

doFrame主要完成了以下工作:

1. 判断mFrameScheduled是否为false,如果为false, 说明还未开始,因为在每次scheduleFrameLocked的时候,mFrameScheduled都会被设置为true

2. 计算当前时间和VSYNC的时间差,如果大于一个VSYNC周期就说明有丢帧,如果有丢帧,计算当前的丢帧数

3. 修正当前帧的时间,这个时间为离startNanos最近,且小于startNanos的一个VSYNC

4.执行5个CallBack

doFrame(long frameTimeNanos, int frame) {
        final long startNanos;
        synchronized (mLock) {
           //1. 判断mFrameScheduled是否为false,如果为false, 说明还未开始,
           //因为在每次scheduleFrameLocked的时候,mFrameScheduled都会被设置为true
            if (!mFrameScheduled) {
                return; // no work to do
            }

            if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
                mDebugPrintNextFrameTimeDelta = false;
                Log.d(TAG, "Frame time delta: "
                        + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
            }

            long intendedFrameTimeNanos = frameTimeNanos;
            //2.计算当前时间和VSYNC的时间差,如果大于一个VSYNC周期就说明有丢帧
            // 如果有丢帧,计算当前的丢帧数,
            startNanos = System.nanoTime();
            final long jitterNanos = startNanos - frameTimeNanos;
            if (jitterNanos >= mFrameIntervalNanos) {
                final long skippedFrames = jitterNanos / mFrameIntervalNanos;
                if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
                    Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
                            + "The application may be doing too much work on its main thread.");
                }
                final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
                if (DEBUG_JANK) {
                    Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
                            + "which is more than the frame interval of "
                            + (mFrameIntervalNanos * 0.000001f) + " ms!  "
                            + "Skipping " + skippedFrames + " frames and setting frame "
                            + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
                }
                //3.修正当前帧的时间,这个时间为离startNanos最近,且小于startNanos的一个VSYNC
                frameTimeNanos = startNanos - lastFrameOffset;
            }

            if (frameTimeNanos < mLastFrameTimeNanos) {
                if (DEBUG_JANK) {
                    Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
                            + "previously skipped frame.  Waiting for next vsync.");
                }
                scheduleVsyncLocked();
                return;
            }

            if (mFPSDivisor > 1) {
                long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
                if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
                    scheduleVsyncLocked();
                    return;
                }
            }

            mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
            mFrameScheduled = false;
            mLastFrameTimeNanos = frameTimeNanos;
        }

        try {
            //4.执行5个CallBack
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
            AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);

            mFrameInfo.markInputHandlingStart();
            doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

            mFrameInfo.markAnimationsStart();
            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
            doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);

            mFrameInfo.markPerformTraversalsStart();
            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

            doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
        } finally {
            AnimationUtils.unlockAnimationClock();
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }

        if (DEBUG_FRAMES) {
            final long endNanos = System.nanoTime();
            Log.d(TAG, "Frame " + frame + ": Finished, took "
                    + (endNanos - startNanos) * 0.000001f + " ms, latency "
                    + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
        }
    }

1.2.3 doCallbacks

doCallbacks主要完成了以下工作:

1.用当前时间戳去校验链表CallbackRecord,由于CallBackQueue是按照dueTime,从头到尾,从小到大排序的

因此,extractDueCallbacksLocked执行逻辑就是,找到第一个比当前时间大的dueTime,然后把这个元素及其后面的

元素都删除,然后在把这个callbacks返回去,当然,如果没有头部callBackRecord都比当前时间大,返回callbacks就为空

2. 如果当前类型问 CALLBACK_COMMIT,且发现前面处理时间过长,就会把当前的frameTimeNanos进行校正

3. 依次执行callBack

void doCallbacks(int callbackType, long frameTimeNanos) {
        CallbackRecord callbacks;
        synchronized (mLock) {
            // We use "now" to determine when callbacks become due because it's possible
            // for earlier processing phases in a frame to post callbacks that should run
            // in a following phase, such as an input event that causes an animation to start.
            //1.用当前时间戳去校验链表CallbackRecord,由于CallBackQueue是按照dueTime,从头到尾,从小到大排序的
            //因此,extractDueCallbacksLocked执行逻辑就是,找到第一个比当前时间大的dueTime,然后把这个元素及其后面的
            //元素都删除,然后在把这个callbacks返回去,当然,如果没有头部callBackRecord都比当前时间大,返回callbacks就为空
            final long now = System.nanoTime();
            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                    now / TimeUtils.NANOS_PER_MS);
            if (callbacks == null) {
                return;
            }
            mCallbacksRunning = true;

            // 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.
            //2. 如果当前类型问 CALLBACK_COMMIT,且发现前面处理时间过长,就会把当前的frameTimeNanos进行校正

            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!  "
                                + "Setting frame time to " + (lastFrameOffset * 0.000001f)
                                + " ms in the past.");
                        mDebugPrintNextFrameTimeDelta = true;
                    }
                    frameTimeNanos = now - lastFrameOffset;
                    mLastFrameTimeNanos = frameTimeNanos;
                }
            }
        }
        try {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
            //3.依次执行callBack
            for (CallbackRecord c = callbacks; c != null; c = c.next) {
                if (DEBUG_FRAMES) {
                    Log.d(TAG, "RunCallback: type=" + callbackType
                            + ", action=" + c.action + ", token=" + c.token
                            + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                }
                c.run(frameTimeNanos);
            }
        } finally {
            synchronized (mLock) {
                mCallbacksRunning = false;
                do {
                    final CallbackRecord next = callbacks.next;
                    recycleCallbackLocked(callbacks);
                    callbacks = next;
                } while (callbacks != null);
            }
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }
  // callback链表本来就是从头到尾,从小到大排序的,因此,extractDueCallbacksLocked执行逻辑就,
  // 找到第一个比当前时间大的dueTime,然后把这个元素及其后面的,元素都删除,
  // 然后在把这个callbacks返回去,当然,如果没有头部callBackRecord都比当前时间大,
  // 返回callbacks就为空
  public CallbackRecord extractDueCallbacksLocked(long now) {
            CallbackRecord callbacks = mHead;
            if (callbacks == null || callbacks.dueTime > now) {
                return null;
            }

            CallbackRecord last = callbacks;
            CallbackRecord next = last.next;
            while (next != null) {
                if (next.dueTime > now) {
                    last.next = null;
                    break;
                }
                last = next;
                next = next.next;
            }
            mHead = next;
            return callbacks;
        }

2. 关键流程

2.1 CALLBACK_INPUT相关流程

2.2 CALLBACK_TRAVERSAL 

2.3 CALLBACK_ANIMATION

最后

以上就是失眠羽毛为你收集整理的显示子系统之:Choreographer1. 关键成员变量和方法2. 关键流程的全部内容,希望文章能够帮你解决显示子系统之:Choreographer1. 关键成员变量和方法2. 关键流程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部