背景价绍
在一个典型的显示系统中,一般包括 CPU、GPU、Display 三个部分, CPU 负责计算帧数据,把计算好的数据交给 GPU,GPU 会对图形数据进行渲染,渲染好后放到 buffer(图像缓冲区) 里存起来,然后 Display(屏幕或显示器)负责把 buffer 里的数据呈现到屏幕上。
由于图像绘制和屏幕读取 使用的是同个 buffer,所以屏幕刷新时可能读取到的是不完整的一帧画面。
由此就设计了双缓存,让绘制和显示器拥有各自的 buffer:GPU 始终将完成的一帧图像数据写入到 Back Buffer,而显示器使用 Frame Buffer,当屏幕刷新时,Frame Buffer 并不会发生变化,当Back buffer准备就绪后,它们才进行交换。
那么什么时候进行两个buffer的交换呢?
当扫描完一个屏幕后,设备需要重新回到第一行以进入下一次的循环,此时有一段时间空隙,称为VerticalBlanking Interval(VBI)。那么,这个时间点就是我们进行缓冲区交换的最佳时间。
VSync(垂直同步)是VerticalSynchronization的简写,它利用VBI时期出现的 vertical sync pulse(垂直同步脉冲)来保证双缓冲在最佳时间点才进行交换。另外,交换是指各自的内存地址,可以认为该操作是瞬间完成。
Choreographer 的引入,主要是配合 Vsync,给上层 App 的渲染提供一个稳定的 Message 处理的时机,也就是 Vsync 信号到来的时候,系统通过对 Vsync 信号周期的调整,来控制每一帧绘制操作的时机。 那为什么 Vsync 周期选择是 16ms (60 fps) ,是因为目前大部分手机的屏幕都是 60Hz 的刷新率,也就是 16ms 刷新一次,系统为了配合屏幕的刷新频率,将 Vsync 的周期也设置为 16ms,每隔 16ms,Vsync 信号到来唤醒 Choreographer 来做 App 的绘制操作,如果每个 Vsync 周期应用都能渲染完成,那么应用的 fps 就是 60 ,给用户的感觉就是非常流畅,这就是引入 Choreographer 的主要作用。
Choreographer 的简介
Choreographer 扮演 Android 渲染链路中承上启下的角色
- 承上:负责接收和处理 App 的各种更新消息和回调,等到 Vsync 到来的时候统一处理。比如集中处理 Input(主要是 Input 事件的处理) 、Animation(动画相关)、Traversal(包括 measure、layout、draw 等操作) ,判断卡顿掉帧情况,记录 CallBack 耗时等
- 启下:负责请求和接收 Vsync 信号。接收 Vsync 事件回调(通过 FrameDisplayEventReceiver.onVsync);请求 Vsync (通过 FrameDisplayEventReceiver.scheduleVsync)
从上面可以看出来, Choreographer 担任的是一个工具人的角色,之所以重要,是因为通过 Choreographer + SurfaceFlinger + Vsync + TripleBuffer 这一套从上到下的机制,保证了 Android App 可以以一个稳定的帧率运行(20fps、90fps 或者 60fps),减少帧率波动带来的不适感。
了解 Choreographer 还可以帮助 App 开发者知道程序每一帧运行的基本原理,也可以加深对 Message、Handler、Looper、MessageQueue、Input、Animation、Measure、Layout、Draw 的理解。
Choreographer 的工作流程
-
Choreographer 初始化
- 初始化 FrameHandler ,绑定 Looper
- 初始化 FrameDisplayEventReceiver,用于与 SurfaceFlinger(native) 建立通信用于接收和请求 Vsync
- 初始化 CallBackQueues
-
SurfaceFlinger 的 appEventThread 唤醒发送 Vsync ,Choreographer 回调 FrameDisplayEventReceiver.onVsync , 进入 Choreographer 的主处理函数 doFrame
-
Choreographer.doFrame 计算掉帧逻辑
-
Choreographer.doFrame 处理 Choreographer 的第一个 callback : input
-
Choreographer.doFrame 处理 Choreographer 的第二个 callback : animation
-
Choreographer.doFrame 处理 Choreographer 的第三个 callback : insets animation
-
Choreographer.doFrame 处理 Choreographer 的第四个 callback : traversal
- traversal-draw 中 UIThread 与 RenderThread 同步数据
-
Choreographer.doFrame 处理 Choreographer 的第五个 callback : commit
-
RenderThread 处理绘制命令,将处理好的绘制命令发给 GPU 处理
-
调用 swapBuffer 提交给 SurfaceFlinger 进行合成(此时 Buffer 并没有真正完成,需要等 CPU 完成后 SurfaceFlinger 才能真正使用)
第一步初始化完成后,后续就会在步骤 2-9 之间循环
源码分析
首先来个引子,在 Activity 的生命周期中,Activity 启动走完 onResume 方法后,会进行 window 的添加。window 添加过程会调用 ViewRootImpl 的 setView() 方法,setView() 方法会调用 requestLayout() 方法来请求绘制布局,requestLayout() 方法内部又会走到 scheduleTraversals() 方法,最后会走到 performTraversals() 方法,接着到了我们熟知的测量、布局、绘制三大流程了。
另外,查看源码发现,当我们使用 ValueAnimator.start()、View.invalidate() 时,最后也是走到 ViewRootImpl 的 scheduleTraversals() 方法。(View.invalidate() 内部会循环获取 ViewParent 直到 ViewRootImpl 的 invalidateChildInParent() 方法,然后走到 scheduleTraversals())
即所有UI的变化都是走到ViewRootImpl的scheduleTraversals()方法。
//ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
//移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
...
//开始三大绘制流程
performTraversals();
...
}
}
scheduleTraversals 方法的主要有以下逻辑:
- 首先使用 mTraversalScheduled 字段保证同时间多次更改只会刷新一次,例如 TextView 连续两次 setText(),也只会走一次绘制流程
- 然后把当前线程的消息队列 Queue 添加了同步屏障,这样就屏蔽了正常的同步消息,保证 VSync 到来后立即执行绘制,而不是要等前面的同步消息
- 调用了 mChoreographer.postCallback() 方法,发送一个会在下一帧执行的回调,即在下一个 VSync 到来时会执行 TraversalRunnable-->doTraversal()--->performTraversals()-->绘制流程
这是 Android 基于 Choreographer 渲染机制的核心代码,下面我们来详细看看 Choreographer 的源码,代码均来自于 cs.android.com/
Choreographer 初始化
Choreographer 的单例初始化
// 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, VSYNC_SOURCE_APP);
if (looper == Looper.getMainLooper()) {
mMainInstance = choreographer;
}
return choreographer;
}
};
调用入口在 ViewRootImpl 的构造函数中
public ViewRootImpl(Context context, Display display) {
......
mChoreographer = Choreographer.getInstance();
......
}
Choreographer 的构造函数
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
mHandler = new FrameHandler(looper);
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
mLastFrameTimeNanos = Long.MIN_VALUE;
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
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));
}
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, new DisplayEventReceiver.VsyncEventData());
break;
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
case MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);
break;
}
}
}
FrameDisplayEventReceiver 简介
Vsync 的注册、申请、接收都是通过 FrameDisplayEventReceiver 这个类, FrameDisplayEventReceiver 继承 DisplayEventReceiver , 有三个比较重要的方法
- onVsync – Vsync 信号回调
- run – 执行 doFrame
- scheduleVsync – 请求 Vsync 信号
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
......
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame,
VsyncEventData vsyncEventData) {
try {
......
mTimestampNanos = timestampNanos;
mFrame = frame;
mLastVsyncEventData = 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);
}
// 此方法位于父类 DisplayEventReceiver 中
public void scheduleVsync() {
......
nativeScheduleVsync(mReceiverPtr);
......
}
}
Choreographer 中 Vsync 的注册
从下面的函数调用栈可以看到,Choreographer 的内部类 FrameDisplayEventReceiver.onVsync 负责接收 Vsync 回调,通知 UIThread 进行数据处理。
那么 FrameDisplayEventReceiver 是通过什么方式在 Vsync 信号到来的时候回调 onVsync 呢?答案是 FrameDisplayEventReceiver 的初始化的时候,最终通过监听文件句柄的形式,其对应的初始化流程如下
frameworks/base/core/java/android/view/Choreographer.java
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
mHandler = new FrameHandler(looper);
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;
......
}
frameworks/base/core/java/android/view/Choreographer.java
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}
frameworks/base/core/java/android/view/DisplayEventReceiver.java
public DisplayEventReceiver(Looper looper, int vsyncSource) {
......
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
vsyncSource, eventRegistration);
}
简单来说,FrameDisplayEventReceiver 的初始化过程中,通过 BitTube(本质是一个 socket pair),来传递和请求 Vsync 事件,当 SurfaceFlinger(native) 收到 Vsync 事件之后,通过 appEventThread 将这个事件通过 BitTube(native) 传给 DisplayEventDispatcher ,DisplayEventDispatcher 通过 BitTube 的接收端监听到 Vsync 事件之后,回调 Choreographer.FrameDisplayEventReceiver.onVsync ,触发开始一帧的绘制。
Choreographer 处理一帧的逻辑
Choreographer 处理绘制的逻辑核心在 Choreographer.doFrame 函数中,从源码可以看到,FrameDisplayEventReceiver.onVsync post 了自己,其 run 方法直接调用了 doFrame 开始一帧的逻辑处理
android/view/Choreographer.java
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
......
mTimestampNanos = timestampNanos;
mFrame = frame;
mLastVsyncEventData = vsyncEventData;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame, mLastVsyncEventData);
}
doFrame 函数主要做下面几件事
- 计算掉帧逻辑
- 记录帧绘制信息
- 依次执行 doCallbacks, callbackType 有 CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_INSETS_ANIMATION、CALLBACK_TRAVERSAL、CALLBACK_COMMIT 以上代码都位于: frameworks/base/core/java/android/view/Choreographer.java
计算掉帧逻辑
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
......
long intendedFrameTimeNanos = frameTimeNanos;
startNanos = System.nanoTime();
final long jitterNanos = startNanos - frameTimeNanos;
if (jitterNanos >= frameIntervalNanos) {
final long skippedFrames = jitterNanos / frameIntervalNanos;
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 % frameIntervalNanos;
if (DEBUG_JANK) {
Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
+ "which is more than the frame interval of "
+ (frameIntervalNanos * 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.");
}
traceMessage("Frame time goes backward");
scheduleVsyncLocked();
return;
}
if (mFPSDivisor > 1) {
long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
if (timeSinceVsync < (frameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
traceMessage("Frame skipped due to FPSDivisor");
scheduleVsyncLocked();
return;
}
......
}
......
}
Choreographer.doFrame 的掉帧检测有几种情况,其中一种根据时间差来计算,Vsync 信号到来的时候会标记一个 start_time ,执行 doFrame 的时候标记一个 end_time ,这两个时间差就是 Vsync 处理时延,也就是掉帧
记录帧绘制信息
doFrame 函数记录从 Vsync time 到 markPerformTraversalsStart 的时间
void doFrame(long frameTimeNanos, int frame) {
......
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
......
// 处理 CALLBACK_INPUT Callbacks
mFrameInfo.markInputHandlingStart();
......
// 处理 CALLBACK_ANIMATION Callbacks
mFrameInfo.markAnimationsStart();
......
// 处理 CALLBACK_INSETS_ANIMATION Callbacks
// 处理 CALLBACK_TRAVERSAL Callbacks
mFrameInfo.markPerformTraversalsStart();
......
// 处理 CALLBACK_COMMIT Callbacks
......
}
执行 Callbacks
void doFrame(long frameTimeNanos, int frame) {
......
// 处理 CALLBACK_INPUT Callbacks
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos, frameIntervalNanos);
......
// 处理 CALLBACK_ANIMATION Callbacks
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos, frameIntervalNanos);
......
// 处理 CALLBACK_INSETS_ANIMATION Callbacks
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos, frameIntervalNanos);
......
// 处理 CALLBACK_TRAVERSAL Callbacks
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos, frameIntervalNanos);
......
// 处理 CALLBACK_COMMIT Callbacks
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos, frameIntervalNanos);
......
}
Input 回调调用栈
一般是执行 ViewRootImpl.ConsumeBatchedInputRunnable
frameworks/base/core/java/android/view/ViewRootImpl.java
final class ConsumeBatchedInputRunnable implements Runnable {
@Override
public void run() {
mConsumeBatchedInputScheduled = false;
if (doConsumeBatchedInput(mChoreographer.getFrameTimeNanos())) {
// If we consumed a batch here, we want to go ahead and schedule the
// consumption of batched input events on the next frame. Otherwise, we would
// wait until we have more input events pending and might get starved by other
// things occurring in the process.
scheduleConsumeBatchedInput();
}
}
}
Input 时间经过处理,最终会传给 DecorView 的 dispatchTouchEvent,进入事件分发流程。
Animation 回调调用栈
一般我们接触的多的是调用 View.postOnAnimation 的时候,会使用到 CALLBACK_ANIMATION
frameworks/base/core/java/android/view/View.java
public void postOnAnimation(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
attachInfo.mViewRootImpl.mChoreographer.postCallback(
Choreographer.CALLBACK_ANIMATION, action, null);
} else {
// Postpone the runnable until we know
// on which thread it needs to run.
getRunQueue().post(action);
}
}
Traversal 调用栈
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//为了提高优先级,先 postSyncBarrier,添加同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
// 真正开始执行 measure、layout、draw
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
// 移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
private void performTraversals() {
// measure 操作
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
|| mHeight != host.getMeasuredHeight() || dispatchApplyInsets ||
updatedConfiguration) {
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
// layout 操作
if (didLayout) {
performLayout(lp, mWidth, mHeight);
}
// draw 操作
if (!cancelDraw) {
performDraw();
}
}
下一帧的 Vsync 请求
由于动画、滑动、Fling 这些操作的存在,我们需要一个连续的、稳定的帧率输出机制。这就涉及到了 Vsync 的请求逻辑,在连续的操作,比如动画、滑动、Fling 这些情况下,每一帧的 doFrame 的时候,都会根据情况触发下一个 Vsync 的申请,这样我们就可以获得连续的 Vsync 信号。
我们比较熟悉的 invalidate 和 requestLayout 都会触发 Vsync 信号请求。
我们下面以 Animation 为例,看看 Animation 是如何驱动下一个 Vsync ,来持续更新画面的。
ObjectAnimator 动画驱动逻辑
frameworks/base/core/java/android/animation/ObjectAnimator.java
public void start() {
AnimationHandler.getInstance().autoCancelBasedOn(this);
super.start();
}
frameworks/base/core/java/android/animation/ValueAnimator.java
private void start(boolean playBackwards) {
......
addAnimationCallback(0); // 动画 start 的时候添加 Animation Callback
......
}
private void addAnimationCallback(long delay) {
......
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
frameworks/base/core/java/android/animation/AnimationHandler.java
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
if (mAnimationCallbacks.size() == 0) {
// post FrameCallback
getProvider().postFrameCallback(mFrameCallback);
}
......
}
// 这里的 mFrameCallback 回调 doFrame,里面 post了自己
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
// post 自己
getProvider().postFrameCallback(this);
}
}
};
调用 postFrameCallback 会走到 mChoreographer.postFrameCallback ,这里就会触发 Choreographer 的 Vsync 请求逻辑
frameworks/base/core/java/android/animation/AnimationHandler.java
private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {
final Choreographer mChoreographer = Choreographer.getInstance();
@Override
public void postFrameCallback(Choreographer.FrameCallback callback) {
mChoreographer.postFrameCallback(callback);
}
@Override
public void postCommitCallback(Runnable runnable) {
mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, runnable, null);
}
@Override
public long getFrameTime() {
return mChoreographer.getFrameTime();
}
@Override
public long getFrameDelay() {
return Choreographer.getFrameDelay();
}
@Override
public void setFrameDelay(long delay) {
Choreographer.setFrameDelay(delay);
}
}
最终调用 Choreographer.postCallbackDelayedInternal 方法 frameworks/base/core/java/android/view/Choreographer.java
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) {
// 请求 Vsync scheduleFrameLocked ->scheduleVsyncLocked-> mDisplayEventReceiver.scheduleVsync ->nativeScheduleVsync
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
通过上面的 Animation.start 设置,利用了 Choreographer.FrameCallback 接口,每一帧都去请求下一个 Vsync
源码小结
-
Choreographer 是线程单例的,而且必须要和一个 Looper 绑定,因为其内部有一个 Handler 需要和 Looper 绑定,一般是 App 主线程的 Looper 绑定
-
DisplayEventReceiver 是一个 abstract class,其 JNI 的代码部分会创建一个IDisplayEventConnection 的 Vsync 监听者对象。这样,来自 AppEventThread 的 VSYNC 中断信号就可以传递给 Choreographer 对象了。当 Vsync 信号到来时,DisplayEventReceiver 的 onVsync 函数将被调用。
-
DisplayEventReceiver 还有一个 scheduleVsync 函数。当应用需要绘制UI时,将首先申请一次 Vsync 中断,然后再在中断处理的 onVsync 函数去进行绘制。
-
Choreographer 定义了一个 FrameCallback interface,每当 Vsync 到来时,其 doFrame 函数将被调用。这个接口对 Android Animation 的实现起了很大的帮助作用。以前都是自己控制时间,现在终于有了固定的时间中断。
-
Choreographer 的主要功能是,当收到 Vsync 信号时,去调用使用者通过 postCallback 设置的回调函数。目前一共定义了五种类型的回调,它们分别是:
- CALLBACK_INPUT : 处理输入事件处理有关
- CALLBACK_ANIMATION : 处理 Animation 的处理有关
- CALLBACK_INSETS_ANIMATION : 处理 Insets Animation 的相关回调
- CALLBACK_TRAVERSAL : 处理和 UI 等控件绘制有关
- CALLBACK_COMMIT : 处理 Commit 相关回调,主要是是用于执行组件 Application/Activity/Service 的 onTrimMemory,在 ApplicationThread 的 scheduleTrimMemory 方法中向 Choreographer 插入的;另外这个 Callback 也提供了一个监测一帧耗时的时机
-
CALLBACK_INPUT 、CALLBACK_ANIMATION 会修改 view 的属性,所以要先于 CALLBACK_TRAVERSAL 执行