Choreographer的作用
1、負(fù)責(zé)接收和處理 App 的各種更新消息和回調(diào),等到 Vsync 到來(lái)的時(shí)候統(tǒng)一處理。比如集中處理 Input(主要是 Input 事件的處理) 、Animation(動(dòng)畫相關(guān))、Traversal(包括 measure、layout、draw 等操作) ,判斷卡頓掉幀情況,記錄 CallBack 耗時(shí)等
2、負(fù)責(zé)請(qǐng)求和接收 Vsync 信號(hào)。接收 Vsync 事件回調(diào)(通過(guò) FrameDisplayEventReceiver.onVsync );請(qǐng)求 Vsync(FrameDisplayEventReceiver.scheduleVsync) .
Choreographer初始化
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;//1
mHandler = new FrameHandler(looper);//2
mDisplayEventReceiver = USE_VSYNC
? new FrameDisplayEventReceiver(looper, vsyncSource)
: null;//3
mLastFrameTimeNanos = Long.MIN_VALUE;
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];//4
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));
}
首先需要一個(gè)Looper,然后通過(guò)Looper來(lái)創(chuàng)建一個(gè)Handler對(duì)象。載創(chuàng)建一個(gè)mDisplayEventReceiver對(duì)象,主要是處理Vsync信號(hào)的回調(diào)和請(qǐng)求。最后初始化一個(gè)回調(diào)隊(duì)列。
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);//1
break;
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();//2
break;
case MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);//3
break;
}
}
}
1表示開(kāi)始下一幀的渲染操作
2表示請(qǐng)求Vsync
3表示處理callback
FrameDisplayEventReceiver
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
@Override
public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
....
mTimestampNanos = timestampNanos;
mFrame = frame;
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
該類繼承DisplayEventReceiver,實(shí)現(xiàn)其兩個(gè)方法為onVsync()和run(),onVsync()主要是處理Vsync信號(hào)的回調(diào),然后將消息設(shè)置成異步,通過(guò)我們的FrameHandler發(fā)送出去。run()則是調(diào)用doFrame(),表示我們接收到Vsync信號(hào)之后,開(kāi)始下一幀的渲染。
onVsync()方法中只是使用mHandler發(fā)送消息到MessageQueue中,不一定是立刻執(zhí)行,如果MessageQueue中前面有較為耗時(shí)的操作,那么就要等完成,才會(huì)執(zhí)行本次的doFrame()。
前面說(shuō)了,F(xiàn)rameDisplayEventReceiver是請(qǐng)求和回調(diào),那請(qǐng)求時(shí)在哪里了?
@UnsupportedAppUsage
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);
}
}
真正的請(qǐng)求是在DisplayEventReceiver類中的scheduleVsync(),里面調(diào)用的是一個(gè)native方法來(lái)進(jìn)行請(qǐng)求Vsync信號(hào)。DisplayEventReceiver 初始化完成后,Choreographer 與 SurfaceFlinger 的 Vsync 信號(hào)傳遞通道就建立好了,后續(xù)有 Vsync 信號(hào)到來(lái)時(shí),就可以沿著這條通道,一路回調(diào)到 Java 層的 Choreographer.FrameDisplayEventReceiver.onVsync 方法。
callback類型
//輸入事件,首先執(zhí)行
public static final int CALLBACK_INPUT = 0;
//動(dòng)畫,第二執(zhí)行
public static final int CALLBACK_ANIMATION = 1;
//繪制,第三執(zhí)行
public static final int CALLBACK_TRAVERSAL = 2;
//提交,最后執(zhí)行,
public static final int CALLBACK_COMMIT = 3;
callback類型四種,其執(zhí)行的順序?yàn)?-》1-》2-》3
執(zhí)行流程
那什么時(shí)候會(huì)用到Choreographer,通過(guò)調(diào)用invalidate()或者requestLayout()方法的時(shí)候,也就是我們需要UI繪制的時(shí)候,需要用到Choreographer。
上面的兩個(gè)方法最終都會(huì)走到scheduleTraversals()。
scheduleTraversals()
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
首先會(huì)設(shè)置一個(gè)同步屏障,然后調(diào)用postCallback()方法.postCallback()方法中繼續(xù)調(diào)用postCallbackDelayed(),最終會(huì)調(diào)用postCallbackDelayedInternal()方法。
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[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);
}
}
}
如果dueTime<=當(dāng)前時(shí)間,則會(huì)去請(qǐng)求Vsync信號(hào),否則通過(guò)handler發(fā)送一條異步消息到隊(duì)列中。
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
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);
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
1、如果系統(tǒng)未開(kāi)啟 VSYNC 機(jī)制,此時(shí)直接發(fā)送 MSG_DO_FRAME 消息到 FrameHandler,此時(shí)直接執(zhí)行 doFrame 方法。
2、Android 4.1 之后系統(tǒng)默認(rèn)開(kāi)啟 VSYNC,在 Choreographer 的構(gòu)造方法會(huì)創(chuàng)建一個(gè) FrameDisplayEventReceiver,scheduleVsyncLocked 方法將會(huì)通過(guò)它申請(qǐng) VSYNC 信號(hào)。
3、isRunningOnLooperThreadLocked 方法,其內(nèi)部根據(jù) Looper 判斷是否在原線程,否則發(fā)送消息到 FrameHandler。最終還是會(huì)調(diào)用 scheduleVsyncLocked 方法申請(qǐng) VSYNC 信號(hào)。
請(qǐng)求Vsync信號(hào)成功之后,就會(huì)走onVsync()回調(diào)。onVsync()中,將接收器本身作為runnable傳入異步消息msg,并使用mHandler發(fā)送msg,最終執(zhí)行的就是doFrame()方法。
doFrame()
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
long intendedFrameTimeNanos = frameTimeNanos;
startNanos = System.nanoTime();
final long jitterNanos = startNanos - frameTimeNanos;
if (jitterNanos >= mFrameIntervalNanos) {
final long skippedFrames = jitterNanos / mFrameIntervalNanos;
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.");
}
scheduleVsyncLocked();
return;
}
if (mFPSDivisor > 1) {
long timeSinceVsync = frameTimeNanos - mLastFrameTimeNanos;
if (timeSinceVsync < (mFrameIntervalNanos * mFPSDivisor) && timeSinceVsync > 0) {
scheduleVsyncLocked();
return;
}
}
mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
}
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
在doFrame方法中,主要做了以下的事:
1、計(jì)算掉幀邏輯
Choreographer.doFrame 的掉幀檢測(cè)比較簡(jiǎn)單,Vsync 信號(hào)到來(lái)的時(shí)候會(huì)標(biāo)記一個(gè) start_time ,執(zhí)行 doFrame 的時(shí)候標(biāo)記一個(gè) end_time ,這兩個(gè)時(shí)間差就是 Vsync處理時(shí)延,也就是掉幀。
這種方法計(jì)算的掉幀,是前一幀的掉幀情況,而不是這一幀的掉幀情況,這個(gè)計(jì)算方法是有缺陷的,會(huì)導(dǎo)致有的掉幀沒(méi)有被計(jì)算到
2、記錄幀繪制信息
Choreographer 中 FrameInfo 來(lái)負(fù)責(zé)記錄幀的繪制信息,doFrame 執(zhí)行的時(shí)候,會(huì)把每一個(gè)關(guān)鍵節(jié)點(diǎn)的繪制時(shí)間記錄下來(lái),我們使用 dumpsys gfxinfo 就可以看到。
3、執(zhí)行 CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL、CALLBACK_COMMIT
最后執(zhí)行的是c.run(frameTimeNanos);
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
((Runnable)action).run();
}
}
最后調(diào)用的是run();
現(xiàn)在我們?cè)賮?lái)看scheduleTraversals()
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
((Runnable)action).run()其實(shí)執(zhí)行的是mTraversalRunnable。
mTraversalRunnable()
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
performTraversals();//1
}
}
從1可以知道,熟悉view的繪制流程的就知道在performTraversals()中會(huì)去執(zhí)行Measure(),Layout(),Draw(),就這樣就形成了一個(gè)閉環(huán)。

小結(jié)
1、Choreographer 是線程單例的,而且必須要和一個(gè) Looper 綁定,因?yàn)槠鋬?nèi)部有一個(gè) Handler 需要和 Looper 綁定,一般是 App 主線程的 Looper 綁定。
2、DisplayEventReceiver 是一個(gè) abstract class,其 JNI 的代碼部分會(huì)創(chuàng)建一個(gè)IDisplayEventConnection 的 Vsync 監(jiān)聽(tīng)者對(duì)象。這樣,來(lái)自 AppEventThread 的 VSYNC 中斷信號(hào)就可以傳遞給 Choreographer 對(duì)象了。當(dāng) Vsync 信號(hào)到來(lái)時(shí),DisplayEventReceiver 的 onVsync 函數(shù)將被調(diào)用。
3、DisplayEventReceiver 還有一個(gè) scheduleVsync 函數(shù)。當(dāng)應(yīng)用需要繪制UI時(shí),將首先申請(qǐng)一次 Vsync 中斷,然后再在中斷處理的 onVsync 函數(shù)去進(jìn)行繪制。
4、Choreographer 定義了一個(gè) FrameCallback interface,每當(dāng) Vsync 到來(lái)時(shí),其 doFrame 函數(shù)將被調(diào)用。這個(gè)接口對(duì) Android Animation 的實(shí)現(xiàn)起了很大的幫助作用。以前都是自己控制時(shí)間,現(xiàn)在終于有了固定的時(shí)間中斷。
5、Choreographer 的主要功能是,當(dāng)收到 Vsync 信號(hào)時(shí),去調(diào)用使用者通過(guò) postCallback 設(shè)置的回調(diào)函數(shù)。目前一共定義了四種類型的回調(diào),它們分別是:
CALLBACK_INPUT : 處理輸入事件處理有關(guān)
CALLBACK_ANIMATION : 處理 Animation 的處理有關(guān)
CALLBACK_TRAVERSAL : 處理和 UI 等控件繪制有關(guān)
CALLBACK_COMMIT : 處理 Commit 相關(guān)回調(diào)
6、CALLBACK_INPUT 、CALLBACK_ANIMATION 會(huì)修改 view 的屬性,所以要先于 CALLBACK_TRAVERSAL 執(zhí)行