public DisplayEventReceiver(Looper looper, int vsyncSource) {
if (looper == null) {
throw new IllegalArgumentException(“looper must not be null”);
}
mMessageQueue = looper.getQueue();
// 注册VSYNC信号监听者
mReceiverPtr = nativeInit(new WeakReference(this), mMessageQueue,
vsyncSource);
mCloseGuard.open(“dispose”);
}
另外 DisplayEventReceiver 内还包括用于申请 VSYNC 信号的 scheduledVsync 方法,
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 {
// 申请VSYNC中断信号
// 会回调onVsync方法
nativeScheduleVsync(mReceiverPtr);
}
}
和用于接收 VSYNC 信号的 onVsync 方法。这样,当应用需要绘制时,通过 scheduledVsync 方法申请 VSYNC 中断,来自 EventThread 的 VSYNC 信号就可以传递到 Choreographer:
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
// 该方法在其子类FrameDisplayEventReceiver中被重写
// 目的是通知Choreographer
}
- CallbackQueue,用于保存通过 postCallback 添加的任务。目前一共定义了四种任务类型,它们分别是:
- CALLBACK_INPUT:优先级最高,和输入事件处理有关。
- CALLBACK_ANIMATION:优先级其次,和 Animation 的处理有关
- CALLBACK_TRAVERSAL:优先级最低,和 UI 绘制任务有关
- CALLBACK_COMMIT:最后执行,和提交任务有关(在 API Level 23 添加)
优先级的高低和处理顺序有关,每当收到 VSYNC 信号时,Choreographer 将首先处理 INPUT 类型的任务,然后是 ANIMATION 类型,最后才是 TRAVERSAL 类型。
通过 Choreographer 添加的任务最后都被封装成 CallbackRecord,同种任务之间按照时间顺序以链表的形式保存在 CallbackQueue 内。
private static final class CallbackRecord {
// 链表,指向下一个
public CallbackRecord next;
// 到期时间
public long dueTime;
// Runnable or FrameCallback
public Object action;
public Object token;
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
// 通过postFrameCallback 或 postFrameCallbackDelayed
// 会执行这里
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
}
CallbackQueue 是一个容量为 4 的数组,分别对应不同的任务类型。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F93oRB0l-1651731139993)(//upload-images.jianshu.io/upload_images/2573196-824cbc10acc6e291.png?imageMogr2/auto-orient/strip|imageView2/2/w/968/format/webp)]
接下来,以 View 的绘制流程为例,从 ViewRootImpl 的 scheduleTraversals 方法开始,其内部通过 Choreographer 的 postCallback 将绘制任务添加到 Chorographer。关于 View 绘制流程的详细分析,可以参考《View 绘制流程之 DecorView 添加至窗口的过程》和《[深入 Activity 三部曲(3)之 View 绘制流程](()》。
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 同步屏障,阻塞所有的同步消息
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 注意mTraversaRunnable是一个Runnable对象
// 通过 Choreographer 发送绘制任务
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
// …
}
}
Choreographer 是线程单例的,大家是否还记得 Android 系统的 Looper 对象也是 线程单例。主线程 Looper 是在 ActivityThread 的 main 方法被创建。如果要在子线程使用 Handler,必须先为其创建一个 Looper 实例。
Choreographer 提供了两种添加任务的方式,postCallback() 和 postFrameCallback(),当然还有对应的 delay 方法。
- postCallback 对应调用 postCallbackDelayed
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
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
- postFrameCallback 对应调用 postFrameCallbackDelayed
public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
if (callback == null) {
throw new IllegalArgumentException(“callback must not be null”);
}
//最终调用postCallbackDelayedInternal
postCallbackDelayedInternal(CALLBACK_ANIMATION,
callback, FRAME_CALLBACK_TOKEN, delayMillis);
}
postCallback 相比 postFrameCallback 更加灵活一些。
它们最终都会调用到 postCallbackDelayedInternal 方法:
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
// 当前时间
final long now = SystemClock.uptimeMillis();
// 加上延迟时间
final long dueTime = now + delayMillis;
// 根据任务类型添加到mCallbackQueues中
// VSYNC信号处理任务具有优先级
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
//表示立即执行,立即申请VSYNC信号
scheduleFrameLocked(now);
} else {
// 在指定时间运行,最终仍然会调用scheduleFrameLocked
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
// 到时根据callbackType在mCallbackQueues中查找执行
msg.arg1 = callbackType;