在Android4.1之后增加了Choreographer機(jī)制,用于同Vsync機(jī)制配合,統(tǒng)一動(dòng)畫、輸入和繪制時(shí)機(jī)。本文以繪制為例來簡(jiǎn)單學(xué)習(xí)下Choreographer。
一、從繪制流程開始
ViewRootImpl的requestLayout開啟繪制流程:
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();//檢查是否在當(dāng)前線程
mLayoutRequested = true;//mLayoutRequested 是否measure和layout布局。
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {//同一幀內(nèi)不會(huì)多次調(diào)用遍歷
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();//攔截同步Message
//Choreographer回調(diào),執(zhí)行繪制操作
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
這里主要關(guān)注兩點(diǎn):
postSyncBarrier : Handler 的同步屏障。它的作用是可以攔截 Looper 對(duì)同步消息的獲取和分發(fā),加入同步屏障之后,Looper 只會(huì)獲取和處理異步消息,如果沒有異步消息那么就會(huì)進(jìn)入阻塞狀態(tài)。也就是說,對(duì)View繪制渲染的處理操作可以優(yōu)先處理(設(shè)置為異步消息)。
Choreographer: 編舞者。統(tǒng)一動(dòng)畫、輸入和繪制時(shí)機(jī)。也是這章需要重點(diǎn)分析的內(nèi)容。
二、Choreographer啟動(dòng)
public ViewRootImpl(Context context, Display display) {
...
//獲取Choreographer實(shí)例
mChoreographer = Choreographer.getInstance();
...
}
frameworks\base\core\java\android\view\Choreographer.java
public static Choreographer getInstance() {
return sThreadInstance.get();
}
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!");
}
return new Choreographer(looper);
}
};
每一個(gè)Looper線程都有自己的Choreographer,其他線程發(fā)送的回調(diào)只能運(yùn)行在對(duì)應(yīng)Choreographer所屬的Looper線程上
private Choreographer(Looper looper) {
mLooper = looper;
mHandler = new FrameHandler(looper);
// 根據(jù)是否使用了VSYNC來創(chuàng)建一個(gè)FrameDisplayEventReceiver對(duì)象
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
mLastFrameTimeNanos = Long.MIN_VALUE;//是指上一次幀繪制時(shí)間點(diǎn)
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());//幀間時(shí)長(zhǎng),一般等于16.7ms
// CALLBACK_LAST + 1 = 4,創(chuàng)建一個(gè)容量為4的CallbackQueue數(shù)組,用來存放4種不同的Callback
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
}
Choreographer類中有一個(gè)Looper和一個(gè)FrameHandler變量。變量USE_VSYNC用于表示系統(tǒng)是否是用了Vsync同步機(jī)制,該值是通過讀取系統(tǒng)屬性debug.choreographer.vsync來獲取的。如果系統(tǒng)使用了Vsync同步機(jī)制,則創(chuàng)建一個(gè)FrameDisplayEventReceiver對(duì)象用于請(qǐng)求并接收Vsync事件,最后Choreographer創(chuàng)建了一個(gè)大小為3的CallbackQueue隊(duì)列數(shù)組,用于保存不同類型的Callback。
這里,不同類型的Callback包括如下4種:
public static final int CALLBACK_INPUT = 0; //輸入
public static final int CALLBACK_ANIMATION = 1; //動(dòng)畫
public static final int CALLBACK_TRAVERSAL = 2; //視圖繪制
public static final int CALLBACK_COMMIT = 3; //提交 ( 這一類型是在API level=23的時(shí)候添加的)

CallbackQueue是一個(gè)容量為4的數(shù)組,每一個(gè)元素作為頭指針,引出對(duì)應(yīng)類型的鏈表,4種事件就是通過這4個(gè)鏈表來維護(hù)的。
而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);
break;
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync(); // 請(qǐng)求VSYNC信號(hào)
break;
case MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);
break;
}
}
}
三、Choreographer執(zhí)行流程

Choreographer提供了兩類添加回調(diào)的方式:postCallback 與 postFrameCallback,當(dāng)然對(duì)應(yīng)類型也包含delay的方法,算上其實(shí)有4個(gè)方法。
postCallback對(duì)應(yīng)的:
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);
}
postFrameCallback對(duì)應(yīng)的:
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);
}
相比之下postCallback更靈活一點(diǎn)。兩者最終都會(huì)調(diào)到:postCallbackDelayedInternal
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
// 當(dāng)前時(shí)間
final long now = SystemClock.uptimeMillis();
// 回調(diào)執(zhí)行時(shí)間,為當(dāng)前時(shí)間加上延遲的時(shí)間
final long dueTime = now + delayMillis;
// obtainCallbackLocked(long dueTime, Object action, Object token)會(huì)將傳入的3個(gè)參數(shù)轉(zhuǎn)換為CallbackRecord(具體請(qǐng)看源碼,非主要部分,此處略過),然后CallbackQueue根據(jù)回調(diào)類型將CallbackRecord添加到鏈表上。
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
// 如果delayMillis=0的話,dueTime=now,則會(huì)馬上執(zhí)行
scheduleFrameLocked(now);
} else {
// 如果dueTime>now,則發(fā)送一個(gè)what為MSG_DO_SCHEDULE_CALLBACK類型的定時(shí)消息,等時(shí)間到了再處理,其最終處理也是執(zhí)行scheduleFrameLocked(long now)方法
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
mCallbackQueues先把對(duì)應(yīng)的callback添加到鏈表上來,然后判斷是否有延遲,如果沒有則會(huì)馬上執(zhí)行scheduleFrameLocked,如果有,則發(fā)送一個(gè)what為MSG_DO_SCHEDULE_CALLBACK類型的定時(shí)消息,等時(shí)間到了再處理,其最終處理也是執(zhí)行scheduleFrameLocked(long now)方法。
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
// 如果使用了VSYNC,由系統(tǒng)值確定
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame on vsync.");
}
if (isRunningOnLooperThreadLocked()) {
// 請(qǐng)求VSYNC信號(hào),最終會(huì)調(diào)到Native層,Native處理完成后觸發(fā)FrameDisplayEventReceiver的onVsync回調(diào),回調(diào)中最后也會(huì)調(diào)用doFrame(long frameTimeNanos, int frame)方法
scheduleVsyncLocked();
} else {
// 在UI線程上直接發(fā)送一個(gè)what=MSG_DO_SCHEDULE_VSYNC的消息,最終也會(huì)調(diào)到scheduleVsyncLocked()去請(qǐng)求VSYNC信號(hào)
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
// 沒有使用VSYNC
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.");
}
// 直接發(fā)送一個(gè)what=MSG_DO_FRAME的消息,消息處理時(shí)調(diào)用doFrame(long frameTimeNanos, int frame)方法
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
這里首先判斷USE_VSYNC,如果使用了VSYNC:走scheduleVsyncLocked,即請(qǐng)求VSYNC信號(hào),最終調(diào)用doFrame,如果沒使用VSYNC,則通過消息執(zhí)行doFrame。
那么我們先簡(jiǎn)單了解下請(qǐng)求VSYNC信號(hào)的流程:
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
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);
}
}
mDisplayEventReceiver 對(duì)應(yīng)的是FrameDisplayEventReceiver,它繼承自 DisplayEventReceiver , 主要是用來接收同步脈沖信號(hào) VSYNC。scheduleVsync()方法通過底層nativeScheduleVsync()向SurfaceFlinger 服務(wù)注冊(cè),即在下一次脈沖接收后會(huì)調(diào)用 DisplayEventReceiver的dispatchVsync()方法。這里類似于訂閱者模式,但是每次調(diào)用nativeScheduleVsync()方法都有且只有一次dispatchVsync()方法回調(diào)。
然后再看看接收VSYNC信號(hào):

底層向應(yīng)用層發(fā)送VSYNC信號(hào),java層通過dispatchVsync()接收,最后回調(diào)在FrameDisplayEventReceiver的onVsync
private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
//忽略來自第二顯示屏的Vsync
if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
scheduleVsync();
return;
}
...
mTimestampNanos = timestampNanos;
mFrame = frame;
//該消息的callback為當(dāng)前對(duì)象FrameDisplayEventReceiver
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
//此處mHandler為FrameHandler
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
可見onVsync()過程是通過FrameHandler向主線程Looper發(fā)送了一個(gè)自帶callback的消息 callback為FrameDisplayEventReceiver。 當(dāng)主線程Looper執(zhí)行到該消息時(shí),則調(diào)用FrameDisplayEventReceiver.run()方法,緊接著便是調(diào)用doFrame。
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // mFrameScheduled=false,則直接返回。
}
long intendedFrameTimeNanos = frameTimeNanos; //原本計(jì)劃的繪幀時(shí)間點(diǎn)
startNanos = System.nanoTime();//保存起始時(shí)間
//由于Vsync事件處理采用的是異步方式,因此這里計(jì)算消息發(fā)送與函數(shù)調(diào)用開始之間所花費(fèi)的時(shí)間
final long jitterNanos = startNanos - frameTimeNanos;
//如果線程處理該消息的時(shí)間超過了屏幕刷新周期
if (jitterNanos >= mFrameIntervalNanos) {
//計(jì)算函數(shù)調(diào)用期間所錯(cuò)過的幀數(shù)
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
//當(dāng)?shù)魩瑐€(gè)數(shù)超過30,則輸出相應(yīng)log
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;
frameTimeNanos = startNanos - lastFrameOffset; //對(duì)齊幀的時(shí)間間隔
}
//如果frameTimeNanos小于一個(gè)屏幕刷新周期,則重新請(qǐng)求VSync信號(hào)
if (frameTimeNanos < mLastFrameTimeNanos) {
scheduleVsyncLocked();
return;
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
//分別回調(diào)CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL事件
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
當(dāng)Vsync事件到來時(shí),順序執(zhí)行4種事件對(duì)應(yīng)CallbackQueue隊(duì)列中注冊(cè)的回調(diào)。
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
//從指定類型的CallbackQueue隊(duì)列中查找執(zhí)行時(shí)間到的CallbackRecord
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
if (callbacks == null) {
return;
}
mCallbacksRunning = true;
}
try {
//由于CallbackQueues是按時(shí)間先后順序排序的,因此遍歷執(zhí)行所有時(shí)間到的CallbackRecord
for (CallbackRecord c = callbacks; c != null; c = c.next) {
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
}
}
按時(shí)間順序先后執(zhí)行CallbackRecord對(duì)應(yīng)的run方法
private static final class CallbackRecord {
public CallbackRecord next;
public long dueTime;
public Object action; // Runnable or FrameCallback
public Object token;
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
}
接開篇講的
void scheduleTraversals() {
...
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
mTraversalRunnable對(duì)應(yīng):
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
run方法被執(zhí)行,所以doTraversal()被執(zhí)行,開啟View的繪制流程。
所以整個(gè)繪制過程總的流程如下所示:

簡(jiǎn)單總結(jié):
- Choreographer支持4種類型事件:輸入、繪制、動(dòng)畫、提交,并通過postCallback在對(duì)應(yīng)需要同步vsync進(jìn)行刷新處進(jìn)行注冊(cè),等待回調(diào)。
- Choreographer監(jiān)聽底層Vsync信號(hào),一旦接收到回調(diào)信號(hào),則通過doFrame統(tǒng)一對(duì)java層4種類型事件進(jìn)行回調(diào)。
參考
https://blog.csdn.net/bluewindtalker/article/details/54017569
https://blog.csdn.net/qian520ao/article/details/80954626
http://gityuan.com/2017/02/25/choreographer/
http://m.itdecent.cn/p/47c866f6fb67