前言
在Android的绘制流程中,会走到ViewRootImpl
里的scheduleTraversals()
函数
java
//代码文件:ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
在这里面我们可以看到有mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
mChoreographer
就是今天我们要分析的对象Choreographer(编舞者)
。
Choreographer
假如把硬件设备性能完全开放,假如GPU制图速率是120FPS(一秒钟出120张图),而屏幕只有60HZ(1秒钟刷新60次),那就会造成一些问题(丢失一些帧数),所以需要Choreographer
进行帧率上的管理。
Choreographer
的引入,主要是配合Vsync
,给上层App的渲染提供一个稳定的绘制处理时机,也就是Vsync(同步信号)
到来的时候,Choreographer
可以接收VSync信号
,统一管理应用的输入、动画、绘制等任务的执行实际。Android的UI绘制任务将在他的同一指挥下完成,这个是引入Choreographer
的作用:
- 业内一般用它来监控应用的帧率;
- Choreographer进行帧率的管理;
- Choreographer他来完成对于16.6ms的时间管理判定以及跳帧处理;
- Choreographer的定位就是去控制,什么时候请求同步信息且推动绘制启动;
ok,看完Choreographer
的介绍后,我们回到上述代码的位置mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
我们往下跟随代码,看看Choreographer
是怎么去跟Vsync(同步信号)
配合,进而绘制界面的。
java
//代码文件:Choreographer.java
public void postCallback(int callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token, 0);
}
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);
}
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG_FRAMES) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + 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);
}
}
}
最终会调用到postCallbackDelayedInternal
方法,首先先把action
存进mCallbackQueues
里,这里的action
就是后续我们要调用到的measure
、layout
、draw
;接着通过判断dueTime
,要么执行scheduleFrameLocked(now);
要么通过mHandler
发送一个Message
,最终还是会执行到scheduleFrameLocked(now);
。
java
//代码文件:Choreographer.java
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
if (USE_VSYNC) {
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame on vsync.");
}
// If running on the Looper thread, then schedule the vsync immediately,
// otherwise post a message to schedule the vsync from the UI thread
// as soon as possible.
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);
if (DEBUG_FRAMES) {
Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
}
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
isRunningOnLooperThreadLocked()
判断如果是在主线程上,则向底层请求同步信号,如果是子线程的绘制消息则通过消息发送,两者最终都是走到scheduleVsyncLocked();
。
java
//代码文件:Choreographer.java
private final FrameDisplayEventReceiver mDisplayEventReceiver;
private void scheduleVsyncLocked() {
mDisplayEventReceiver.scheduleVsync();
}
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}
......
}
这里调用到mDisplayEventReceiver.scheduleVsync();
,我们需要到mDisplayEventReceiver的父类
看它的scheduleVsync()
具体实现。
java
//代码文件:DisplayEventReceiver.java
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);
}
}
最终调用到nativeScheduleVsync(mReceiverPtr);
,是一个native调用
,主要作用是去底层找SurfaceFlinger
请求vSync同步信号
(具体过程参考:blog.csdn.net/j383575602/...
等底层垂直同步信号发送过来后,会回调dispatchVsync
方法:
java
//代码文件:DisplayEventReceiver.java
// Called from native code.
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
onVsync(timestampNanos, builtInDisplayId, frame);
}
进而调用到子类FrameDisplayEventReceiver
的onVsync
方法:
java
//代码文件:Choreographer.java
private final FrameDisplayEventReceiver mDisplayEventReceiver;
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, 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);
}
}
可以看到创建了一个Message
,并且在初始化Message
时,给callback
赋值了,所以后续会执行到run()
方法,进而执行到doFrame()
方法。
doFrame()
函数中执行了应用层的callback
,基本上包含了一帧的渲染工作:
java
//代码文件:oreographer.java
void doFrame(long frameTimeNanos, int frame) {
//自带了掉帧计算
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.");
}
}
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
}
其中CALLBACK_ANIMATION
是处理动画相关的逻辑,而CALLBACK_TRAVERSAL
则会调用到ViewRootImpl
的performTraversals() 函数
,从而执行到我们所熟悉的View的measure
、layout
、draw
三大流程。