Skip to content

Choreographer详解

ZhangPan edited this page Jul 28, 2025 · 13 revisions

在Android 4.1版本之前,由于屏幕的绘制没有一个良好的绘制周期和缓冲,丢帧和屏幕撕裂的问题非常严重。

Google 在 2012 年的 I/O 大会上宣布 Project Butter 计划,并在 Android 4.1 中正式开始实施,以优化 UI 渲染流畅性的问题。Project Butter 对 Android Display 系统进行了重构优化,引入了三个核心元素,即 VSYNCTriple BufferingChoreographer,本文重点深入学习 Choreographer 有关的知识。

一、基础概念

  • VSYNC 垂直同步

GPU 厂商开发用于防止屏幕撕裂的技术方案,全称 Vertical Synchronization,即垂直同步,可简单的把它理解为一种时钟中断

  • 刷新频率(Refresh Rate)

屏幕在一秒内刷新画面的次数,刷新频率取决于硬件的固定参数,单位:Hz(赫兹)。如常见的 60 Hz、144 Hz,即每秒钟刷新 60 次或 144 次。

  • 逐行扫描

显示器并不是一次性将画面的像素显示到屏幕上,而是从左到右边,从上到下逐行扫描显示像素点,不过这一过程快到人眼无法察觉到变化。以 60 Hz 刷新率的屏幕为例,即 1000 / 60 ≈ 16ms。

  • 帧速率 (Frame Rate)

表示 GPU 在一秒内绘制操作的帧数,单位:fps,全称 Frames Per Second,即每秒传输帧数。如在电影界采用 24 帧的速度足够使画面运行的非常流畅。而 Android 系统则采用更加流畅的 60 fps,即每秒钟绘制 60 帧画面。

二、 Choreographer 概述

Choreographer 直译为:舞蹈编导编舞者,本质是一个 Java 类。简单来说,Choreographer 主要作用是协调输入、动画、和绘制等任务的执行时机,它从显示子系统接收定时脉冲(如垂直同步),然后安排渲染下一个显示 Frame 的部分工作。

还可以使用 Choreographer 来监测应用的帧率,结合自定义 FrameCallback 使用,在下一个显示 Frame 被渲染时将触发 FrameCallback 接口类获取渲染完成时间。

Choreographer 与 Vsync 配合,为上层 APP 的渲染提供一个稳定的 Message 处理时机。假定当前手机的是 60Hz 的刷新率,即 16.6ms 刷新一次。系统为了配合屏幕的刷新频率,将 Vsync 的周期也设置为 16.6ms。每隔16.6ms,Vsync信号就会唤醒 Chroeographer来执行APP的绘制操作。

三、 Choreographer 的初始化

public final class Choreographer {
	// ThreadLocal 存储 Choreographer
    private static final ThreadLocal<Choreographer> sThreadInstance =
            new ThreadLocal<Choreographer>() {
        @Override
        protected Choreographer initialValue() {
        	// 获取当前线程的 Looper 对象
            Looper looper = Looper.myLooper();
            // 如果当前线程没有关联 Looper 则抛出异常提示
            if (looper == null) {
                throw new IllegalStateException("The current thread must have a looper!");
            }
            // 使用当前线程的 Looper 创建 Choreographer 实例,注意这里传的第二个参数 source 是 VSYNC_SOURCE_APP
            // 这个值是 DisplayEventReceiver.VSYNC_SOURCE_APP 也就是 0
            // 与 ISurfaceComposer.h 中的 VsyncSource.eVsyncSourceApp 值保持同步,代表的就是 AppEventThread
            Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
            // 如果 Looper 是主线程的,则将 choreographer 赋值给 mMainInstance
            if (looper == Looper.getMainLooper()) {
                mMainInstance = choreographer;
            }
            return choreographer;
        }
    };
	// Choreographer 静态实例
    private static volatile Choreographer mMainInstance;
    
	// 线程级单例,获取调用线程的 Choreographer 实例,必须由已关联有 Looper 的线程调用,否则抛出异常
	public static Choreographer getInstance() {
	    return sThreadInstance.get();
	}
}

可以看到 Choreographer 内部有一个静态的 sThreadInstance,由于 sThreadInstance 是一个静态成员变量。因此 sThreadInstance 会在 Choreographer 的类加载时被初始化。源码中重写了 ThreadLocal 的 initialValue 方法。在这个方法中首先获取了当前线程的 Looper,然后实例化了Choreographer,并将其存入到了 ThreadLocal 中。

另外,Choreographer 还提供了一个 getInstance 方法。从 sThreadInstance 中来获取 Choreographer 。由此可见 Choreographer 与 Looper 一样都是一个线程级别的单例。

Choreographer 在其构造方法中会初始化一些用到的数据。其构造方法如下:

public final class Choreographer {

    public static final int CALLBACK_COMMIT = 4;
    private static final int CALLBACK_LAST = CALLBACK_COMMIT;
    
    private Choreographer(Looper looper, int vsyncSource) {
    	// 当前线程的 Looper
        mLooper = looper;
        // 创建 FrameHandler 处理消息
        mHandler = new FrameHandler(looper);
        // 是否启用 VSync,启用则创建 FrameDisplayEventReceiver 对象接收 VSync 脉冲信号
        mDisplayEventReceiver = USE_VSYNC
                ? new FrameDisplayEventReceiver(looper, vsyncSource)
                : null;
        // 初始化上一个 frame 渲染的时间点
        mLastFrameTimeNanos = Long.MIN_VALUE;
    	// getRefreshRate() 获取刷新率,Android 手机屏幕是 60Hz 的刷新频率
    	// 计算帧率,即渲染一帧的时间约等于 16666.66ns ≈ 16.6ms 
        mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
    	// 创建回调队列 CallbackQueue 默认容量大小是 5 的链表数组,存放要执行的输入、动画、绘制等任务
        mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
        for (int i = 0; i <= CALLBACK_LAST; i++) {
        	// 每个子元素为链表,用于存相同类型的任务:输入、动画、绘制等任务
        	//(CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL)
            mCallbackQueues[i] = new CallbackQueue();
        }
        // b/68769804: For low FPS experiments.
        setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
    }
}

Choreographer 的构造方法的核心有以下几点:

  • 首先实例化了一个 FrameHandler,FrameHandler 是一个继承自 Handler 的类。这个后边再分析。
  • 根据 USE_VSYNC 变量判断当前是否启用 Vsync 同步机制。该值是通过读取系统属性 debug.choreographer.vsync 来获取的,Android 在 4.1 之后默认启用该机制。因此这里默认创建了 FrameDisplayEventReceiver 对象用户请求并接受 Vsync 信号。
  • 给 mLastFrameTimeNanos 赋初始值,mLastFrameTimeNanos 表示上一帧渲染的开始时间。
  • 根据刷新了计算每帧画面的时间间隔并保存到 mFrameIntervalNanos
  • 初始化一个 mCallbackQueues 的数组,这个数组长度为5,表示 5 种不同的任务类型,例如输入(CALLBACK_INPUT)动画(CALLBACK_ANIMATION)、**绘制(CALLBACK_TRAVERSAL)**等类型。数组的成员类型为 CallbackQueue。CallbackQueue 内部封装了一个 CallbackRecord 类型的链表,每种类型任务可能有多个,相同的类型以链表形式存储。

构造方法中初始化了一些成员变量,其中比较重要的两个成员变量是 FrameHandler 与 FrameDisplayEventReceiver

FrameHandler

FrameHandler 是 Choreographer 的一个内部类,源码如下:

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, new DisplayEventReceiver.VsyncEventData());
                break;
            case MSG_DO_SCHEDULE_VSYNC:
                doScheduleVsync();
                break;
            case MSG_DO_SCHEDULE_CALLBACK:
                doScheduleCallback(msg.arg1);
                break;
        }
    }
}
  • MSG_DO_FRAME 当收到 Vsync 信号后执行 doFrame 开始渲染页面帧。
  • MSG_DO_SCHEDULE_VSYNC 向系统底层请求下一次VSYNC信号
  • MSG_DO_SCHEDULE_CALLBACK 请求执行延迟任务回调*

FrameDisplayEventReceiver

FrameDisplayEventReceiver 也是 Choreographer 中的一个内部类。 源码如下:

private final class FrameDisplayEventReceiver extends DisplayEventReceiver
        implements Runnable {
    private boolean mHavePendingVsync;
    private long mTimestampNanos;
    private int mFrame;
    private final VsyncEventData mLastVsyncEventData = new VsyncEventData();

    FrameDisplayEventReceiver(Looper looper, int vsyncSource, long layerHandle) {
        super(looper, vsyncSource, /* eventRegistration */ 0, layerHandle);
    }

    // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
    // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
    // for the internal display implicitly.
    @Override
    public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
            VsyncEventData vsyncEventData) {
        try {
            if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW,
                        "Choreographer#onVsync "
                                + vsyncEventData.preferredFrameTimeline().vsyncId);
            }
            // 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;
            mLastVsyncEventData.copyFrom(vsyncEventData);
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

    @Override
    public void run() {
        mHavePendingVsync = false;
        doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
    }
}

可以看到 FrameDisplayEventReceiver 继承了 DisplayEventReceiver。DisplayEventReceiver 是一个抽象类。当 Vsync 信号到来时会调用 DisplayEventReceiver 的 dispatchVsync 方法,在这个方法中又调用了 onVsync。而FrameDisplayEventReceiver 重写了 onVsync 方法。

onVsync 方法的核心是构建了一个 Message ,这个 Message 持有 FrameDisplayEventReceiver,FrameDisplayEventReceiver 实现了 Runnable 接口。 因此在通过 FrameHandler 发送消息后最终会执行 FrameDisplayEventReceiver 的 run 方法。

而 run 方法中的核心则是调用了 doFrame 去完成帧的绘制逻辑。doFrame 方法的源码如下:

public final class Choreographer {
    // 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);
	// ...
	void doFrame(long frameTimeNanos, int frame,
            DisplayEventReceiver.VsyncEventData vsyncEventData) {
        final long startNanos; 
        final long frameIntervalNanos = vsyncEventData.frameInterval; // 帧间隔
        try {
			// ...
            synchronized (mLock) {
                // ...
				// 设置将要处理的当前帧的时间戳
                long intendedFrameTimeNanos = frameTimeNanos;
                startNanos = System.nanoTime();	// 记录实际开始执行当前 frame 的时间
                final long jitterNanos = startNanos - frameTimeNanos; // 计算时间差值
                if (jitterNanos >= frameIntervalNanos) { // 时间差值大于等于帧间隔,即发生了跳帧
                    final long skippedFrames = jitterNanos / frameIntervalNanos; // 计算跳帧数
                    // 跳帧超过 30 打印日志提醒,SKIPPED_FRAME_WARNING_LIMIT 通过读取
                    // 系统属性 debug.choreographer.skipwarning 来获取的,默认是 30
                    if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
                        Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
                                + "The application may be doing too much work on its main thread.");
                    }
                    // 计算实际开始当前 frame 的时间戳与帧间隔的偏移值
                    final long lastFrameOffset = jitterNanos % frameIntervalNanos;
                    // ...
                    // 修正偏移值,下一帧的时间戳开始值要减去计算得出的偏移值
                    frameTimeNanos = startNanos - lastFrameOffset; 
                }

                if (frameTimeNanos < mLastFrameTimeNanos) {
                    // ...
                    traceMessage("Frame time goes backward");
                    // 当前帧的时间小于上一个帧的时间,可能是由于先前跳帧的缘故,申请并等待下一次 VSync 信号到来
                    scheduleVsyncLocked();
                    return;
                }

                if (mFPSDivisor > 1) {
                    long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
                    if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
                        traceMessage("Frame skipped due to FPSDivisor");
                        // 由于 FPSDivisor 导致跳帧,继续申请并等待下一次 VSync 信号到来
                        scheduleVsyncLocked();
                        return;
                    }
                }
				// 记录当前 Frame 信息
                mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id,
                        vsyncEventData.frameDeadline, startNanos, vsyncEventData.frameInterval);
                // 收到 VSync 信号当前帧调度完,mFrameScheduled 标志位重置为 false,以便下一轮请求使用
                mFrameScheduled = false;
                mLastFrameTimeNanos = frameTimeNanos; // 记录上一次 Frame 渲染的时间
                mLastFrameIntervalNanos = frameIntervalNanos; // 记录上一次 Frame 渲染的帧间隔
                mLastVsyncEventData = vsyncEventData; // 记录上一次 VSync 事件信息
            }
			// 动画锁定为当前线程的固定值
            AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
			// 按照事件类型的优先级执行 CallBack
            mFrameInfo.markInputHandlingStart();
            // 输入事件,首先执行
            doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos, frameIntervalNanos);
            mFrameInfo.markAnimationsStart();
            // 动画事件,在 CALLBACK_INSETS_ANIMATION 之前执行
            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos, frameIntervalNanos);
            // 插入更新动画事件,INPUT 和 ANIMATION 后面执行,TRAVERSAL 之前执行
            doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos, frameIntervalNanos);
			// 处理布局和绘制事件,在处理完上述异步消息之后运行
            mFrameInfo.markPerformTraversalsStart();
            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos, frameIntervalNanos);
			// 提交,和提交任务有关(在 API Level 23 添加),最后执⾏,遍历完成的提交操作,⽤来修正动画启动时间
            doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos, frameIntervalNanos);
        } finally {
            AnimationUtils.unlockAnimationClock();
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
		// ...
    }
    // ...
}
  • 获取正在运行的 Java 虚拟机的当前时间,单位为纳秒,然后从数组链表 mCallbackQueues 中获取指定类型的链表 CallbackQueue,之后调用 CallbackQueue # extractDueCallbacksLocked() 方法并传入刚才获取到的时间,来确定链表 CallbackQueue 中是否有 CallbackRecord 的执行时间已经到了。参见 3.4 回调队列 CallBackQueue 中的图示和介绍。
  • 遍历获取到的 callbacks 链表获取 CallbackRecord 对象,然后执行 CallbackRecord 对象的 run() 方法。
	void doCallbacks(int callbackType, long frameTimeNanos, long frameIntervalNanos) {
        CallbackRecord callbacks;
        synchronized (mLock) {
        	// 获取正在运行的 Java 虚拟机的当前时间,单位为纳秒,以此来确定回调何时执行
            // 因为帧中的前期处理阶段可能会发布应在下一阶段运行的回调,例如导致动画启动的输入事件
            final long now = System.nanoTime();
            // 从数组链表 mCallbackQueues 中获取指定类型的链表
            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                    now / TimeUtils.NANOS_PER_MS);
            if (callbacks == null) { // 没有查找到 callbackType 对应的链表,则直接返回
                return;
            }
            mCallbacksRunning = true;

            // 对于 CALLBACK_COMMIT 类型的事件要更新调整其执行时间、不过多讨论
            if (callbackType == Choreographer.CALLBACK_COMMIT) {
                // ...
            }
        }
        try {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
            // 遍历 callbacks 链表获取 CallbackRecord 对象
            for (CallbackRecord c = callbacks; c != null; c = c.next) {
                ......
                // 执行 CallbackRecord 对象的 run() 方法
                c.run(frameTimeNanos);
            }
        } finally {
            synchronized (mLock) {
                mCallbacksRunning = false;
                // 回收 callbacks,置空其内部 CallbackRecord 保存的信息,重组并赋值给 mCallbackPool 链表
                do {
                    final CallbackRecord next = callbacks.next;
                    recycleCallbackLocked(callbacks);
                    callbacks = next;
                } while (callbacks != null);
            }
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }
    // ...

CallbackRecord 的 run() 方法中,根据 token 判断当前回调类型,这里暂时不分析 FRAME_CALLBACK_TOKEN 类型的,只分析 Runnable 并执行其 run() 方法,在 1. 初探 Choreographer 的使用 中通过 Choreographer # postCallback() 方法提交一个任务 TraversalRunnable,将任务 TraversalRunnable 和执行时间一起被封装成 CallbackRecord,因此这里执行的就是 TraversalRunnable 的 run() 方法。

Choreographer 在系统源码中的应用

上一节中分析了 Choreographer 的初始化过程。其中提到 mCallbackQueues 数组中存储了5 种不同类型的任务类型。下面举两个类型的 CallbackQueue 在系统源码中使用的例子来更全面的了解 Choreographer 。

1. View的渲染流程与 Choreographer

在分析学习 View 绘制流程有关的源码时,刷新 View 可以使用 View # invalidate() 方法 或 View # requestLayout() 方法,但不管调用哪一个方法,流程都会走到 ViewRootImpl # scheduleTraversals() 方法,代码如下:

// ViewRootImpl 初始化时会实例化 Choreographer
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
    final Choreographer mChoreographer;
    public ViewRootImpl(Context context, Display display, IWindowSession session,
            boolean useSfChoreographer) {
        ......
        mChoreographer = useSfChoreographer
                ? Choreographer.getSfInstance() : Choreographer.getInstance();
        ......
	}

	@UnsupportedAppUsage
	void scheduleTraversals() {
		// 注意这个标志位,多次调用时只有这个标志位为 false 时才有效,保证同时有多次调用时只会执行一次
	    if (!mTraversalScheduled) {
	        mTraversalScheduled = true;
	        // 通过 MessageQueue # postSyncBarrier() 设置 Handler 的同步屏障消息
	        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
	        // Choreographer 通过 postCallback 提交一个任务,mTraversalRunnable 是要执行的回调
	        // 注意这里 token 传值为 null
	        mChoreographer.postCallback(
	                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
	        if (!mUnbufferedInputDispatch) {
	            scheduleConsumeBatchedInput();
	        }
	        notifyRendererOfFramePending();
	        pokeDrawLockIfNeeded();
	    }
	}
}

在 scheduleTraversals 中会通过 Choreographer 的 postCallback 提交一个 CALLBACK_TRAVERSAL 的Runnable。postCallback 源码如下:

@UnsupportedAppUsage
@TestApi
public void postCallback(int callbackType, Runnable action, Object token) {
    postCallbackDelayed(callbackType, action, token, 0);
}

/**
 * Posts a callback to run on the next frame after the specified delay.
 * <p>
 * The callback runs once then is automatically removed.
 * </p>
 *
 * @param callbackType The callback type.
 * @param action The callback action to run during the next frame after the specified delay.
 * @param token The callback token, or null if none.
 * @param delayMillis The delay time in milliseconds.
 *
 * @see #removeCallback
 * @hide
 */
@UnsupportedAppUsage
@TestApi
public 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);
}

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(now);
        } else {
            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
            msg.arg1 = callbackType;
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, dueTime);
        }
    }
}

最终,在 postCallbackDelayedInternal 方法中,获取了 CALLBACK_TRAVERSAL 对应的 CallbackQueue,并调用了其 addCallbackLocked 将 Runnable 作为参数传入。addCallbackLocked 源码如下:

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;
}

可以看到上述代码 action 封装到了 CallbackRecord 中,并根据 dueTime 将其插入到了链表的合适位置。

2. Android 动画与 Choreographer

ValueAnimator 是 Android 动效中经常用到的一个类,它的使用方法如下:

   ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1);
   valueAnimator.setDuration(200);
   valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
       @Override
       public void onAnimationUpdate(ValueAnimator animation) {
         int animatedValue = (int) animation.getAnimatedValue();
         Log.e("ValueAnimator","animatedValue-------"+animatedValue);
       }
    });
    valueAnimator.start();

ValueAnimator 的实现其实也和 Choreographer 有关系。看下 ValueAnimator#start 的源码:

private void start(boolean playBackwards) {

 	// ...
    addAnimationCallback(0);

    // ... 
}

start 方法中调用了 addAnimationCallback 方法。addAnimationCallback 源码如下:

private void addAnimationCallback(long delay) {
    if (!mSelfPulse) {
        return;
    }
    getAnimationHandler().addAnimationFrameCallback(this, delay);
}

又调用了 AnimationHandler 的 addAnimationFrameCallback 方法,addAnimationFrameCallback 方法源码如下:

public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
    if (mAnimationCallbacks.size() == 0) {
        getProvider().postFrameCallback(mFrameCallback);
    }
	// ...
}

getProvider 方法获取到的是一个 MyFrameCallbackProvider 的实例,它的 postFrameCallback 源码如下:

public void postFrameCallback(Choreographer.FrameCallback callback) {
    mChoreographer.postFrameCallback(callback);
}

可见这里是调用了 Choreographer 的 postFrameCallback 方法。继续看下 postFrameCallback 的源码:

public void postFrameCallback(FrameCallback callback) {
    postFrameCallbackDelayed(callback, 0);
}

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);
}

可以看到,这里最终跟 View 的渲染流程一样调用了 postCallbackDelayedInternal 方法,不同的是这里的类型是 CALLBACK_ANIMATION。

五、Choreographer 与 Vsync

参考: https://blog.csdn.net/u010347226/article/details/125172662

公众号:玩转安卓Dev

Java基础

面向对象与Java基础知识

Java集合框架

JVM

多线程与并发

设计模式

Kotlin

Android

项目相关问题

Android基础知识

Android消息机制

Android Binder

View事件分发机制

Android屏幕刷新机制

View的绘制流程

Activity启动

Framework

性能优化

Jetpack&系统View

第三方框架实现原理

计算机网络

算法

Clone this wiki locally