Choreographer(编舞者)

官方解释

/*** Coordinates the timing of animations, input and drawing.* <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>* Applications typically interact with the choreographer indirectly using* higher level abstractions in the animation framework or the view hierarchy.* Here are some examples of things you can do using the higher-level APIs.* </p>* <ul>* <li>To post an animation to be processed on a regular time basis synchronized with* display frame rendering, use {@link android.animation.ValueAnimator#start}.</li>* <li>To post a {@link Runnable} to be invoked once at the beginning of the next display* frame, use {@link View#postOnAnimation}.</li>* <li>To post a {@link Runnable} to be invoked once at the beginning of the next display* frame after a delay, use {@link View#postOnAnimationDelayed}.</li>* <li>To post a call to {@link View#invalidate()} to occur once at the beginning of the* next display frame, use {@link View#postInvalidateOnAnimation()} or* {@link View#postInvalidateOnAnimation(int, int, int, int)}.</li>* <li>To ensure that the contents of a {@link View} scroll smoothly and are drawn in* sync with display frame rendering, do nothing.  This already happens automatically.* {@link View#onDraw} will be called at the appropriate time.</li>* </ul>* <p>* However, there are a few cases where you might want to use the functions of the* choreographer directly in your application.  Here are some examples.* </p>* <ul>* <li>If your application does its rendering in a different thread, possibly using GL,* or does not use the animation framework or view hierarchy at all* and you want to ensure that it is appropriately synchronized with the display, then use* {@link Choreographer#postFrameCallback}.</li>* <li>... and that's about it.</li>* </ul>* <p>* Each {@link Looper} thread has its own choreographer.  Other threads can* post callbacks to run on the choreographer but they will run on the {@link Looper}* to which the choreographer belongs.* </p>*/
  • . 协调动画、输入和绘图的时间

  • . 当 choreographer 从子显示系统 接受到定时脉冲(例如垂直脉冲),然后会将 工作 作为下一个显示帧 的一部分,显示。

  • . 应用程序,通常和 choreographer 交互,是直接使用 动画框架 或者 视图层次的 高级抽象。

    • 将要处理的动画按固定时间同步发布 显示帧渲染 ——android.animation.ValueAnimator#start
    • 发布一个{@link Runnable},在下一帧显示开始前用——View#postOnAnimation
    • 发布一个调用 {@link View#invalidate()},在下一帧显示开始前调用——View#postInvalidateOnAnimation()、View#postInvalidateOnAnimation(int, int, int, int)
    • 确保{@link View}的内容平滑地滚动并被绘制进来,同步显示在帧渲染中,不做任何事。这已经自动发生了。
      {@link View#onDraw}将在适当的时间被调用。
  • 有些情况需要我们直接使用 choreographer

    • 如果 应用 在不同的线程渲染,例如GL
    • 或者完全不适用动画框架,或者视图层次
      如果 想确保和 显示同步,可以,通过 Choreographer#postFrameCallback 达到目的。
  • 每一个线程都有自己的choreographer,其它线程可以发送 回调,运行在choreographer,但是他们将会运行在 choreographer 所属的 Looper中。

概况

public final class Choreographer {private static final ThreadLocal<Choreographer> sThreadInstance =new ThreadLocal<Choreographer>() {@Overrideprotected Choreographer initialValue() {Looper looper = Looper.myLooper();if (looper == null) {throw new IllegalStateException("The current thread must have a looper!");}Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);if (looper == Looper.getMainLooper()) {mMainInstance = choreographer;}return choreographer;}};// Thread local storage for the SF choreographer.private static final ThreadLocal<Choreographer> sSfThreadInstance =new ThreadLocal<Choreographer>() {@Overrideprotected Choreographer initialValue() {Looper looper = Looper.myLooper();if (looper == null) {throw new IllegalStateException("The current thread must have a looper!");}return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER);}};// Enable/disable vsync for animations and drawing.//从系统获取,是否支持使用垂直同步private static final boolean USE_VSYNC = SystemProperties.getBoolean("debug.choreographer.vsync", true);//从系统中获取是否使用帧时间
// Enable/disable using the frame time instead of returning now.private static final boolean USE_FRAME_TIME = SystemProperties.getBoolean("debug.choreographer.frametime", true);//从系统中,获取跳帧的阀值// Set a limit to warn about skipped frames.// Skipped frames imply jank.private static final int SKIPPED_FRAME_WARNING_LIMIT = SystemProperties.getInt("debug.choreographer.skipwarning", 30);   /*******************handler 想关*************/private final FrameHandler mHandler;//mHandler 中Message的类型//刷新当前这一帧private static final int MSG_DO_FRAME = 0;//做VSYNC的信号同步private static final int MSG_DO_SCHEDULE_VSYNC = 1;// //将当前任务加入执行队列private static final int MSG_DO_SCHEDULE_CALLBACK = 2;    /*******************handler 想关*************///接受native 层,垂直同步的回调方法private final FrameDisplayEventReceiver mDisplayEventReceiver;//缓存中没在使用的 CallbackRecord private CallbackRecord mCallbackPool;//存储不同类型的 CallbackQueue(存储 CallbackRecord )private final CallbackQueue[] mCallbackQueues;//frame是否开始绘制 private boolean mFrameScheduled;//mCallbacks 是否在运行private boolean mCallbacksRunning;//上一次刷新时间private long mLastFrameTimeNanos;//屏幕刷新时间private long mFrameIntervalNanos;private boolean mDebugPrintNextFrameTimeDelta;private int mFPSDivisor = 1;/*** Must be kept in sync with CALLBACK_* ints below, used to index into this array.* @hide*/private static final String[] CALLBACK_TRACE_TITLES = {"input", "animation", "traversal", "commit"};/*** Callback type: Input callback.  Runs first.* @hide*///输入回调,首先执行public static final int CALLBACK_INPUT = 0;/*** Callback type: Animation callback.  Runs before traversals.* @hide*/@TestApi//动画回调,在CALLBACK_TRAVERSAL  回调之前执行public static final int CALLBACK_ANIMATION = 1;/*** Callback type: Traversal callback.  Handles layout and draw.  Runs* after all other asynchronous messages have been handled.* @hide*///处理,layout 和 draw ,开始于,在所有异步消息处理完之后。public static final int CALLBACK_TRAVERSAL = 2;/*** Callback type: Commit callback.  Handles post-draw operations for the frame.* Runs after traversal completes.  The {@link #getFrameTime() frame time} reported* during this callback may be updated to reflect delays that occurred while* traversals were in progress in case heavy layout operations caused some frames* to be skipped.  The frame time reported during this callback provides a better* estimate of the start time of the frame in which animations (and other updates* to the view hierarchy state) actually took effect.* @hide*/public static final int CALLBACK_COMMIT = 3;private static final int CALLBACK_LAST = CALLBACK_COMMIT;
}

choreographer 类似于Looper ,是以ThreadLocal 副本的形式,存储在Thread 中。

CallbackRecord
public final class Choreographer {// All frame callbacks posted by applications have this token.//应用程序发布的所有 帧回调 ,都使用  FRAME_CALLBACK_TOKEN  作为tokenprivate static final Object FRAME_CALLBACK_TOKEN = new Object() {public String toString() { return "FRAME_CALLBACK_TOKEN"; }};...private static final class CallbackRecord {//单链表结构,每个节点  持有下个CallbackRecord 的引用(next)public CallbackRecord next;//发生的时间public long dueTime;//执行动作,有runnable 或者 帧的回调public Object action; // Runnable or FrameCallback//根据token ,区分 action public Object token;//回调记录的执行public void run(long frameTimeNanos) {if (token == FRAME_CALLBACK_TOKEN) {((FrameCallback)action).doFrame(frameTimeNanos);} else {((Runnable)action).run();}}}..../*** Implement this interface to receive a callback when a new display frame is* being rendered.  The callback is invoked on the {@link Looper} thread to* which the {@link Choreographer} is attached.*///帧呈现的回调public interface FrameCallback {/*** Called when a new display frame is being rendered.* <p>* This method provides the time in nanoseconds when the frame started being rendered.* The frame time provides a stable time base for synchronizing animations* and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}* or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame* time helps to reduce inter-frame jitter because the frame time is fixed at the time* the frame was scheduled to start, regardless of when the animations or drawing* callback actually runs.  All callbacks that run as part of rendering a frame will* observe the same frame time so using the frame time also helps to synchronize effects* that are performed by different callbacks.* </p><p>* Please note that the framework already takes care to process animations and* drawing using the frame time as a stable time base.  Most applications should* not need to use the frame time information directly.* </p>** @param frameTimeNanos The time in nanoseconds when the frame started being rendered,* in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}* to convert it to the {@link SystemClock#uptimeMillis()} time base.*///帧开始显示的时间(纳秒)public void doFrame(long frameTimeNanos);}}
CallbackQueue
public final class Choreographer {//废弃的CallbackRecord  的链表private CallbackRecord mCallbackPool;//根据 执行时间+ action + token 组装成 CallbackRecord private CallbackRecord obtainCallbackLocked(long dueTime, Object action, Object token) {//先用缓存的mCallbackPool 表头节点 CallbackRecord callback = mCallbackPool;//如果缓存的callback  为空则新建一个CallbackRecordif (callback == null) {callback = new CallbackRecord();} else {//如果callback  不为空,则mCallbackPool 指向 缓存列表头节点的下一个节点mCallbackPool = callback.next;callback.next = null;}callback.dueTime = dueTime;callback.action = action;callback.token = token;return callback;}//回收掉从列表移除的CallbackRecord  ,加入到 mCallbackPool 链表的头部private void recycleCallbackLocked(CallbackRecord callback) {callback.action = null;callback.token = null;callback.next = mCallbackPool;mCallbackPool = callback;}...//CallbackRecord 节点类型的链表,是以执行时间由 早到晚排列      private final class CallbackQueue {//CallbackQueue 列表的头节点private CallbackRecord mHead;//链表中添加 action(FrameCallback/Runnable)public void addCallbackLocked(long dueTime, Object action, Object token) {// 生成一个 CallbackRecord CallbackRecord callback = obtainCallbackLocked(dueTime, action, token);CallbackRecord entry = mHead;//CallbackQueue 头节点为空,则callback  赋值为头节点if (entry == null) {mHead = callback;return;}//如果callback 的执行时间,小于 链表的头节点的执行时间,则callback 加入到表头if (dueTime < entry.dueTime) {callback.next = entry;mHead = callback;return;}//遍历链表,根据时间,将callback 插入到列表中while (entry.next != null) {if (dueTime < entry.next.dueTime) {callback.next = entry.next;break;}entry = entry.next;}entry.next = callback;}//移除 action(FrameCallback/Runnable)public void removeCallbacksLocked(Object action, Object token) {CallbackRecord predecessor = null;for (CallbackRecord callback = mHead; callback != null;) {final CallbackRecord next = callback.next;if ((action == null || callback.action == action)&& (token == null || callback.token == token)) {if (predecessor != null) {predecessor.next = next;} else {mHead = next;}recycleCallbackLocked(callback);} else {predecessor = callback;}callback = next;}}}//判断  CallbackQueue 中是否有可执行的  节点public boolean hasDueCallbacksLocked(long now) {// 头节点时间都比now 时间早的话,那么链表中没有可执行的节点return mHead != null && mHead.dueTime <= now;}//根据now 时间,从链表中提取可以执行的  CallbackRecord 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;}...
}
Choreographer 对象的获取
//Choreographer.java
//单例构造方法:从当前线程中 ,获取 实例public static Choreographer getInstance() {return sThreadInstance.get();}private Choreographer(Looper looper, int vsyncSource) {mLooper = looper;mHandler = new FrameHandler(looper);//当系统使用 垂直信号的时候,创建VSYNC的信号接受对象mDisplayEventReceiver = USE_VSYNC? new FrameDisplayEventReceiver(looper, vsyncSource): null;//初始化上一次frame渲染的时间点mLastFrameTimeNanos = Long.MIN_VALUE;//计算帧率,也就是一帧所需的渲染时间,getRefreshRate是刷新率,一般是60mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());//根据回调类型(CALLBACK_INPUT ,CALLBACK_ANIMATION ,CALLBACK_TRAVERSAL ),实例化 mCallbackQueues mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];for (int i = 0; i <= CALLBACK_LAST; i++) {mCallbackQueues[i] = new CallbackQueue();}// b/68769804: For low FPS experiments.setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));}
FrameDisplayEventReceiver (继承自DisplayEventReceiver )
public abstract class DisplayEventReceiver {/*** 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;/*** When retrieving vsync events, this specifies that the vsync event should happen whenever* Surface Flinger is processing a frame.* <p>* Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h*/public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1;private static final String TAG = "DisplayEventReceiver";private final CloseGuard mCloseGuard = CloseGuard.get();//初始化后,获得一个句柄private long mReceiverPtr;// We keep a reference message queue object here so that it is not// GC'd while the native peer of the receiver is using them.private MessageQueue mMessageQueue;private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,MessageQueue messageQueue, int vsyncSource);private static native void nativeDispose(long receiverPtr);@FastNativeprivate static native void nativeScheduleVsync(long receiverPtr);/*** Creates a display event receiver.** @param looper The looper to use when invoking callbacks.*/public DisplayEventReceiver(Looper looper) {this(looper, VSYNC_SOURCE_APP);}/*** Creates a display event receiver.** @param looper The looper to use when invoking callbacks.* @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values.*/public DisplayEventReceiver(Looper looper, int vsyncSource) {if (looper == null) {throw new IllegalArgumentException("looper must not be null");}mMessageQueue = looper.getQueue();//获取当前线程的 mMessageQueue  ,调用本地nativeInit 方法mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,vsyncSource);mCloseGuard.open("dispose");}//当 对象被回收的时候,执行该方法@Overrideprotected void finalize() throws Throwable {try {dispose(true);} finally {super.finalize();}}/*** Disposes the receiver.*/public void dispose() {dispose(false);}private void dispose(boolean finalized) {if (mCloseGuard != null) {if (finalized) {mCloseGuard.warnIfOpen();}mCloseGuard.close();}if (mReceiverPtr != 0) {nativeDispose(mReceiverPtr);mReceiverPtr = 0;}mMessageQueue = null;}/*** Called when a vertical sync pulse is received.* The recipient should render a frame and then call {@link #scheduleVsync}* to schedule the next vertical sync pulse.** @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()}* timebase.* @param builtInDisplayId The surface flinger built-in display id such as* {@link SurfaceControl#BUILT_IN_DISPLAY_ID_MAIN}.* @param frame The frame number.  Increases by one for each vertical sync interval.*///当收到垂直同步脉冲时候,调用//timestampNanos:  脉冲的时间戳//builtInDisplayId: 显示的displayId //frame:帧号。为每个垂直同步间隔增加1public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {}/*** Called when a display hotplug event is received.** @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}* timebase.* @param builtInDisplayId The surface flinger built-in display id such as* {@link SurfaceControl#BUILT_IN_DISPLAY_ID_HDMI}.* @param connected True if the display is connected, false if it disconnected.*///当接收到显示热插拔事件时调用public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {}/*** Schedules a single vertical sync pulse to be delivered when the next* display frame begins.*///在下一帧开始前,发一个垂直同步信号public void scheduleVsync() {if (mReceiverPtr == 0) {Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "+ "receiver has already been disposed.");} else {nativeScheduleVsync(mReceiverPtr);}}// Called from native code.@SuppressWarnings("unused")private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {onVsync(timestampNanos, builtInDisplayId, frame);}// Called from native code.@SuppressWarnings("unused")private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {onHotplug(timestampNanos, builtInDisplayId, connected);}//负责,接收系统发出来的垂直同步信号,和 向系统发出信号
private final class FrameDisplayEventReceiver extends DisplayEventReceiverimplements Runnable {//是否有将要执行的 垂直同步信号private boolean mHavePendingVsync;private long mTimestampNanos;//显示帧数private int mFrame;public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {super(looper, vsyncSource);}//接受到垂直同步信号@Overridepublic void onVsync(long timestampNanos, int builtInDisplayId, int frame) {// Ignore vsync from secondary display.// This can be problematic because the call to scheduleVsync() is a one-shot.// We need to ensure that we will still receive the vsync from the primary// display which is the one we really care about.  Ideally we should schedule// vsync for a particular display.// At this time Surface Flinger won't send us vsyncs for secondary displays// but that could change in the future so let's log a message to help us remember// that we need to fix this.//当接收到的同步信号时,如果builtInDisplayId 不是 BUILT_IN_DISPLAY_ID_MAIN 重新调用 scheduleVsync 获取一个垂直同步信号if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {Log.d(TAG, "Received vsync from secondary display, but we don't support "+ "this case yet.  Choreographer needs a way to explicitly request "+ "vsync for a specific display to ensure it doesn't lose track "+ "of its scheduled vsync.");scheduleVsync();return;}// Post the vsync event to the Handler.// The idea is to prevent incoming vsync events from completely starving// the message queue.  If there are no messages in the queue with timestamps// earlier than the frame time, then the vsync event will be processed immediately.// Otherwise, messages that predate the vsync event will be handled first.long now = System.nanoTime();//如果接收到的信号发生时间大于大于当前时间,则置为当前时间if (timestampNanos > now) {Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f)+ " ms in the future!  Check that graphics HAL is generating vsync "+ "timestamps using the correct timebase.");timestampNanos = now;}if (mHavePendingVsync) {Log.w(TAG, "Already have a pending vsync event.  There should only be "+ "one at a time.");} else {mHavePendingVsync = true;}mTimestampNanos = timestampNanos;mFrame = frame;Message msg = Message.obtain(mHandler, this);msg.setAsynchronous(true);//发送message,通过handler  执行到 下面的run 方法mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);}@Overridepublic void run() {//将是否有将要处理信号标志,置为falsemHavePendingVsync = false;//执行都Frame 方法doFrame(mTimestampNanos, mFrame);}}
  • scheduleVsync : 向系发出 垂直同步信号,CPU ,GPU 接收到信号,开始处理帧数据
  • onVsync(long timestampNanos, int builtInDisplayId, int frame) :接收到系统 返回来的垂直同步信号。当CPU ,GPU 处理完帧数据的时候,回调到该方法,告诉Display 开始处理已经ok的对应帧数据。
doFrame :处理帧数据
public final class Choreographer {//两帧的时间间隔
private long mFrameIntervalNanos;private Choreographer(Looper looper, int vsyncSource) {mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());}//获取系统的刷新频率(FPS)private static float getRefreshRate() {DisplayInfo di = DisplayManagerGlobal.getInstance().getDisplayInfo(Display.DEFAULT_DISPLAY);return di.getMode().getRefreshRate();}...void doFrame(long frameTimeNanos, int frame) {final long startNanos;synchronized (mLock) {//是否有需要处理的 帧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;//系统当前时间startNanos = System.nanoTime();//获取时间差final long jitterNanos = startNanos - frameTimeNanos;//如果时间差大于 系统的帧时间间隔if (jitterNanos >= mFrameIntervalNanos) {//计算相差的帧数final long skippedFrames = jitterNanos / mFrameIntervalNanos;//SKIPPED_FRAME_WARNING_LIMIT系统默认 丢帧警告数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.");}//重置将要执行帧的时间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.");}//发送垂直同步信号(mDisplayEventReceiver.scheduleVsync())scheduleVsyncLocked();return;}//mFPSDivisor :设置FPS devisor来降低FPS,一般默认是1if (mFPSDivisor > 1) {long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {scheduleVsyncLocked();return;}}mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);//置为falsemFrameScheduled = false;//重置上一帧时间mLastFrameTimeNanos = frameTimeNanos;}try {Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");//去设置动画AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);mFrameInfo.markInputHandlingStart();// Input callback 类型callbackdoCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);mFrameInfo.markAnimationsStart();//Animation callback 类型callback doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);mFrameInfo.markPerformTraversalsStart();// Traversal callback 类型callbackdoCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);//CALLBACK_COMMIT 类型 callbackdoCallbacks(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.");}}...
}
doCallbacks
public final class Choreographer {//是否有callbackRecord 在执行private boolean mCallbacksRunning;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.final long now = System.nanoTime();//callbackType 的链表中,根据now 选择执行  符合条件的callbacks // 详见上面 所讲  CallbackQueuecallbacks = 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.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]);//callbacks 到 链表表尾 直接所有节点,执行run 方法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;//移除执行完的callbackRecorddo {final CallbackRecord next = callbacks.next;recycleCallbackLocked(callbacks);callbacks = next;} while (callbacks != null);}Trace.traceEnd(Trace.TRACE_TAG_VIEW);}}
}
FrameHandler
public final class Choreographer {private final FrameHandler mHandler;private final FrameDisplayEventReceiver mDisplayEventReceiver;void doScheduleVsync() {synchronized (mLock) {//如果有frame 在处理if (mFrameScheduled) {scheduleVsyncLocked();}}}private void scheduleVsyncLocked() {mDisplayEventReceiver.scheduleVsync();}private final class FrameHandler extends Handler {public FrameHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_DO_FRAME://执行某帧,查看上面  doFramedoFrame(System.nanoTime(), 0);break;case MSG_DO_SCHEDULE_VSYNC://发送垂直同步信号 doScheduleVsync();break;case MSG_DO_SCHEDULE_CALLBACK://执行某类类型的 callback列表doScheduleCallback(msg.arg1);break;}}}void doScheduleCallback(int callbackType) {synchronized (mLock) {//如果没有帧在处理if (!mFrameScheduled) {final long now = SystemClock.uptimeMillis();//请参阅读上面所讲 CallbackQueuesif (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {scheduleFrameLocked(now);}}}}private void scheduleFrameLocked(long now) {// 如果没有帧在执行if (!mFrameScheduled) {mFrameScheduled = true;//如果使用垂直信号if (USE_VSYNC) {if (DEBUG_FRAMES) {Log.d(TAG, "Scheduling next frame on vsync.");}// If running on the Looper thread, then schedule the vsync immediately,// otherwise post a message to schedule the vsync from the UI thread// as soon as possible.//如果在主线程if (isRunningOnLooperThreadLocked()) {//发送垂直同步信号scheduleVsyncLocked();} else {//发送异步消息 插入,消息链表表头Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);msg.setAsynchronous(true);mHandler.sendMessageAtFrontOfQueue(msg);}} else {//如果没有使用垂直同步,//计下一帧时间final long nextFrameTime = Math.max(mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);if (DEBUG_FRAMES) {Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");}//发送MSG_DO_FRAME 类型异步消息Message msg = mHandler.obtainMessage(MSG_DO_FRAME);msg.setAsynchronous(true);mHandler.sendMessageAtTime(msg, nextFrameTime);}}}
}

如果想绘制某一帧,必须先发送垂直同步信号,在FrameDisplayEventReceiver 的 onVsync 方法中,接收到回调后,才开始 doFrame()->doCallBack()

CallbackQueue 数组中,添加,移除 对应的 CallbackRecord
public final class Choreographer {/***************************添加 runnable****************************/@TestApi//添加runnablepublic void postCallback(int callbackType, Runnable action, Object token) {postCallbackDelayed(callbackType, action, token, 0);}
@TestApipublic void postCallbackDelayed(int callbackType,Runnable action, Object token, long delayMillis) {if (action == null) {throw new IllegalArgumentException("action must not be null");}if (callbackType < 0 || callbackType > CALLBACK_LAST) {throw new IllegalArgumentException("callbackType is invalid");}postCallbackDelayedInternal(callbackType, action, token, delayMillis);}
/***************************添加 runnable****************************//***************************添加 FrameCallback ****************************///添加 FrameCallBack
public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {if (callback == null) {throw new IllegalArgumentException("callback must not be null");}postCallbackDelayedInternal(CALLBACK_ANIMATION,callback, FRAME_CALLBACK_TOKEN, delayMillis);}/***************************添加 FrameCallback ****************************/private void postCallbackDelayedInternal(int callbackType,Object action, Object token, long delayMillis) {if (DEBUG_FRAMES) {Log.d(TAG, "PostCallback: type=" + callbackType+ ", action=" + action + ", token=" + token+ ", delayMillis=" + delayMillis);}synchronized (mLock) {final long now = SystemClock.uptimeMillis();//计算执行时间final long dueTime = now + delayMillis;//加入对应类型的链表中mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);//如果执行时间小于等于当前时间if (dueTime <= now) {//立即执行 scheduleFrameLocked,该方法上午已讲scheduleFrameLocked(now);} else {Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);msg.arg1 = callbackType;msg.setAsynchronous(true);//通过handler 定时执行 scheduleFrameLocked,该方法上午已讲mHandler.sendMessageAtTime(msg, dueTime);}}}
//移除FrameCallback public void removeFrameCallback(FrameCallback callback) {if (callback == null) {throw new IllegalArgumentException("callback must not be null");}removeCallbacksInternal(CALLBACK_ANIMATION, callback, FRAME_CALLBACK_TOKEN);}
//移除Runnable@TestApipublic void removeCallbacks(int callbackType, Runnable action, Object token) {if (callbackType < 0 || callbackType > CALLBACK_LAST) {throw new IllegalArgumentException("callbackType is invalid");}removeCallbacksInternal(callbackType, action, token);}private void removeCallbacksInternal(int callbackType, Object action, Object token) {if (DEBUG_FRAMES) {Log.d(TAG, "RemoveCallbacks: type=" + callbackType+ ", action=" + action + ", token=" + token);}synchronized (mLock) {mCallbackQueues[callbackType].removeCallbacksLocked(action, token);if (action != null && token == null) {//MessageQueue中 移除 callbackType 和 action 对应的 message mHandler.removeMessages(MSG_DO_SCHEDULE_CALLBACK, action);}}}}

编舞者的大体流程,已经过了一边。大体流程:

Choreographer ——编舞者相关推荐

  1. Android编舞者类Choreographer小结

    Android编舞者类Choreographer小结 作用 编舞者类的作用主要是控制绘制节奏,用于发起一次vsync垂直同步信号的监听,当垂直同步信号来的时候会回调注册的Runnable或者FramC ...

  2. android 编舞者的使用

    android 编舞者的使用 1 编舞者Choreographer 的基本常识可以参考其他的博主,在这里主要是针对我使用的时候理解的,请取其精华即可. 使用编舞者 Choreographer 主要是在 ...

  3. Android系统的编舞者Choreographer

    个人博客地址 http://dandanlove.com/ 前言 上一篇文章 Android的16ms和垂直同步以及三重缓存 解释了手机流畅性的问题,并在文章中提到了在Android4.1中添加的Vs ...

  4. Choreographer原理及应用

    平时看博客或者学知识,学到的东西比较零散,没有独立的知识模块概念,而且学了之后很容易忘.于是我建立了一个自己的笔记仓库 (一个我长期维护的笔记仓库,感兴趣的可以点个star~你的star是我写作的巨大 ...

  5. [总]Android高级进阶之路

    个人Android高级进阶之路,目前按照这个目录执行,执行完毕再做扩展!!!!! 一.View的绘制 1)setContentView()的源码分析 2)SnackBar的源码分析 3)利用decor ...

  6. Android应用优化之流畅度优化实操

    上一篇流畅度概念向大家详细地描述了VSync机制和Choreographer编舞者的用法.可能所讲解的内容偏向理论概念,因此这篇是流畅度优化实操,整篇主要分三层,UI层.代码逻辑层.IO层来讲述各个优 ...

  7. 微信Android客户端的卡顿监控方案

    2021.8.1  Matrix 2.0 TraceCanary新增了以下功能 微信Android客户端的卡顿监控方案 https://mp.weixin.qq.com/s/3dubi2GVW_rVF ...

  8. Android工程师进阶第九课 Android优化实战

    第24讲:APK 如何做到包体积优化? 关于 APK Size 的优化,网上有很多版本的介绍.但是因为每个项目的背景.实现方式都不尽相同,导致各个项目之间能列出的共性相对较少.所以这节课我主要分享一下 ...

  9. 「Android渲染」图像是怎样显示到屏幕上的?

    我们每天花很多时间盯着手机屏幕,不知道你有没有好奇过: 手机屏幕上的这些东西是怎么显示出来的? 这时候来了一位Android程序员(当然也可以是iOS或者是前端程序员)说: 这里显示的其实是一个Vie ...

最新文章

  1. POJ 3974-Palindrome
  2. asp.net中的MD5加密
  3. css固定表格表头(各浏览器通用)
  4. 创维37K05HR黑屏有声音故障维修
  5. 暴力字符匹配算法的C语言实现
  6. 大并发下程序出错_Python并发编程理论篇
  7. Oracle数据库中的dual表
  8. java切面获取异常日志_spring aop 配置切面,记录系统异常存入log日志
  9. 代码块是什么?该如何使用?
  10. boot spring 启动 文本_springboot 选择启动某个配置文件
  11. php put怎么接收文件,php,restful_PHP PUT方式传文件的话,如何获取文件内容呢 ?,php,restful,http - phpStudy...
  12. python label显示图片_Python3 tkinter基础 Label imag显示图片
  13. linux没有无线wifi密码忘记,新版tplink无线密码(wifi密码)忘记了怎么办?
  14. win10连不上网,几种尝试
  15. PIXHAWK飞控固件及代码基础介绍
  16. 学习笔记21.07.09:绘制色块图
  17. 局部路径规划算法-DWA动态窗口法
  18. ckeditor KindEditor eWebEditor WQeditor FreeTextbox Tinymce 几款在线编辑器的比较(附各版本demo下载地址)
  19. arm-none-eabi-gcc编译、链接选项详解
  20. 郑州达内计算机学校,郑州达内编程培训,四个月高薪就业

热门文章

  1. Webpack学习笔记(官网教程)
  2. springboot2.7集成spring-boot-starter-data-elasticsearch
  3. 如何利用历史数据预测罕见现象的发生
  4. spark 的第一个程序 WordCount(详细注释版)
  5. 创业元老崔姗姗回归背后,百度变革进入深水区
  6. 为何写机器人课程博客并一直坚持?(2021)
  7. 360浏览器保存网页html,如何设置360浏览器网页保存类型默认为html
  8. 【数据结构】各种数据结构的简单特点
  9. 杀手机器人的漫长过程继续
  10. 欧洲最大的港口与三星IT子公司合作测试区块链运输