「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」
Choreographer初识(1)
上次介绍了初始化的过程以及两个重要的类FrameHandler和FrameDisplayEventReceiver
下面我们继续进行分析
Choreographer 处理每一帧
doFrame()是处理每一帧操作的核心。
这里主要做了两部分处理,一部分是掉帧计算,另一部分是处理回调。
掉帧计算
//frameTimeNanos时间戳
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}
if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
mDebugPrintNextFrameTimeDelta = false;
Log.d(TAG, "Frame time delta: "
+ ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
}
//计算掉帧逻辑
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
frameTimeNanos = startNanos - lastFrameOffset;
}
//...
}
frameTimeNanos是Vsync信号到达时的时间戳,startNanos指的是真正去处理Vsync的时间戳,这两个时间差值就是 Vsync 信号的处理时延,即掉帧时间。,根据延迟的时间间隔获取延迟周期跳过的帧数。
回调的响应
//frameTimeNanos时间戳
void doFrame(long frameTimeNanos, int frame) {
//第二阶段
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
// 处理 CALLBACK_INPUT Callbacks响应输入
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
//响应动画
// 处理 CALLBACK_ANIMATION Callbacks
// 处理 CALLBACK_INSETS_ANIMATION Callbacks
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
//响应绘制流程
// 处理 CALLBACK_TRAVERSAL Callbacks
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
//处理commit回调,修正最后一帧的时间戳。
// 处理 CALLBACK_COMMIT Callbacks
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
相面分别对着几个响应回调进行分析:
Input调用栈
用户进行input交互后,doCallBacks方法内最终执行的是ConsumeBatchedInputRunnable,之后会走到DecorView.dispatchTouchEvent(),后续进行一系列touch event事件分发。
animation调用栈
动画执行时,Choreographer.doFrame() 会响应 AnimationHandler 内部的 Choreographer.FrameCallback.doFrame(),然后执行到 ValueAnimator.onAnimationUpdate(),这个方法也就是业务测实现动画逻辑的地方。
动画完成后,执行 Choreographer.scheduleVsyncLocked() 调度下一个 Vsync(“调度 Vsync” 部分会再讲到),再次执行下一帧的动画流程。
traversal 调用栈
traversal 过程主要是指 View 的 测绘,布局,绘制视图。invalidate()和requestLayout() 都会触发重绘流程。