在学习Choreographer之前我们应该知道view的一些知识:
界面变化原因是view数据发生了变化,view数据变化的原因有:
- 创建了一个新的Window。创建一个新的Window一般来说也就意味着新的Activity的启动,加载一个XML布局到的decorView中。源码解读
- 添加了一个新的View。通过调用ViewGroup#addView方法添加一个新的View到ViewGroup
- 更新了已有的View。 以上的问题都会引起ViewRootImpl的requestLayout调用。
Choreographer 源码解析
以下源码解析来自Android api:29
从ViewRootImpl的requestLayout开始:
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;//是否是measure和layout布局
scheduleTraversals();
}
}
@UnsupportedAppUsage
void scheduleTraversals() {
if (!mTraversalScheduled) { //同一帧不多次调用
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();//注解1
//Choreographer回调,执行绘制操作
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
注解1: postSyncBarrier:发送屏障消息,使handler的除异步消息其他消息的进入阻塞状态,也就意味着其他ui消息无法被处理。
mChoreographer发送一个回调函数。mChoreographer是在ViewRootImpl构造方法中被初始化
public ViewRootImpl(Context context, Display display) {
mChoreographer = Choreographer.getInstance();//是个线程间单例
}
/**
* Gets the choreographer for the calling thread. Must be called from
* a thread that already has a {@link android.os.Looper} associated with it.
*
* @return The choreographer for this thread.
* @throws IllegalStateException if the thread does not have a looper.
*/
public static Choreographer getInstance() {
return sThreadInstance.get();
}
// Thread local storage for the SF choreographer.
private static final ThreadLocal<Choreographer> sSfThreadInstance =
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, VSYNC_SOURCE_SURFACE_FLINGER);
}
};
每一个looper线程都有一个独立的Choreographer,每个Choreographer处理所在线程的事件。
private Choreographer(Looper looper, int vsyncSource) {
mLooper = looper;
mHandler = new FrameHandler(looper);
mDisplayEventReceiver =
? 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));
}
初始化了三个东西:
- mHandler:用于处理延时消息
- mDisplayEventReceiver:处理Vsync信号脉冲(请求和接受)
- mCallbackQueues 大小为5的数组,数组头为链表头,(数组+链表)
- CALLBACK_INPUT 输入事件
- CALLBACK_INSETS_ANIMATION 插图动画
- CALLBACK_ANIMATION 动画
- CALLBACK_TRAVERSAL 视图绘制
- CALLBACK_COMMIT 提交
Choreographer的postCallback流程图如下:
两种callback都都会回调到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);
}
}
}
此方法处理两件事:1.将事件加入CallbackQueues中以对应type为头的链表中。2.计算时间
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 {
....
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
判断是否使用USE_VSYNC ,这个是系统决定。这里只分析使用Vsync的情况: 请求VSYNC信号脉冲,这一步会回调到native层,native中会将ui元数据对SurfaceFlinger服务进行数据处理,最后将会回调到FrameDisplayEventReceiver的onVsync方法,然后回调doFrame方法。
@UnsupportedAppUsage
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}
...
long intendedFrameTimeNanos = frameTimeNanos;
startNanos = System.nanoTime();
final long jitterNanos = startNanos - frameTimeNanos;//计算时间差
if (jitterNanos >= mFrameIntervalNanos) {
//时差大与16ms
//处理帧对齐
}
if (frameTimeNanos < mLastFrameTimeNanos) {
//小于一屏的刷新时间
}
...
}
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中做了两件事:
- 判断VSYNC信号脉冲返回时与发送时的时间差:
- 如果大与屏幕刷新率 帧对齐;
- 如果小于一次的屏幕刷新时间,重新申请VSYNC脉冲。
- 回调各种刚开始时记录的callback。
执行doCallback事件其实就是执行,mTraversalRunnable。
总结
- ViewRootImpl#requestLayout为Choreographer发送一个callback事件,Choreographer通过请求VSYNC信号脉冲来处理callback事件。
- 系统每16ms发送一次VSYNC信号脉冲,当ViewRootImpl#requestLayout的两次调用之间