Choreographer 源码阅读笔记
2017-10-12 16:43
337 查看
Choreographer对象是线程独立的,获取该对象的线程必须要是一个
Looper线程:
// Thread local storage for the choreographer. 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); } }; /** * 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(); } private Choreographer(Looper looper) { mLooper = looper; mHandler = new FrameHandler(looper); mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : 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(); } }
Choreographer在我的理解看来,稍微有点类似于
Handler,它内部会处理3种回调。
// 这些回调都是之前注册进去的。注意顺序。 doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);// 输入/触摸事件的回调 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);// 属性动画的回调 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);// 绘制的回调
我们平常接触的view的绘制流程是从
doTraversal()开始的,那么怎么调用至
doTraversal()呢?其实就是由
Choreographer来负责的。我们先从头说起,正常我们调用
invalidate()或者
requestLayout()会最终调用至
ViewRootImpl中的
scheduleTraversals();方法。
// ViewRootImpl中 void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; // 这里给队列中添加了一个同步阻塞器,用于保证重绘的优先执行 mTraversalBarrier = mHandler.getLooper().postSyncBarrier(); // 注册回调,该回调就执行了一个doTraversal()方法。 mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); } } final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
这里我们要注意一个小细节,就是添加同步阻塞器的那行代码,后续在
Choreographer中可以发现,内部发送的
Message都是异步消息。这也就保证了重绘逻辑的执行。
从源码可知,我们向
Choreographer注册了一个
Choreographer.CALLBACK_TRAVERSAL类型的回调,这个事件的注册最终会执行到
Choreographer中的
postCallbackDelayedInternal()方法。
// 参数中的action 就是我们注册的事件 private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) { if (DEBUG) { Log.d(TAG, "PostCallback: type=" + callbackType + ", action=" + action + ", token=" + token + ", delayMillis=" + delayMillis); } // 把之前注册的回调放入mCallbackQueues数组中 synchronized (mLock) { final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; // 这里的mCallbackQueues是一个回调队列的数组,通过callbackType来获得对应事件类型的队列,这里的action会被封装成一个CallbackRecord对象添加至队列。 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); } } }
这里,
mHandler是一个
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(); break; case MSG_DO_SCHEDULE_CALLBACK: // 这里最终是调用scheduleFrameLocked(now);方法。 doScheduleCallback(msg.arg1); break; } } }
我们将事件存至队列中,然后去执行
scheduleFrameLocked(long now);方法。
private void scheduleFrameLocked(long now) { if (!mFrameScheduled) { mFrameScheduled = true;// 请求一次,绘制一次。一一对应的。 if (USE_VSYNC) {// 高版本都是true。一般都是走这里 if (DEBUG) { 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();// 接收VSYNC消息 } else {// 不在主线程,发送消息至主线程队列前端。 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); msg.setAsynchronous(true); mHandler.sendMessageAtFrontOfQueue(msg); } } // end if (USE_VSYNC) else {// 这里直接走doFrame(long frameTimeNanos, int frame) // 自己计算时间。sFrameDelay=10ms。差不多就是100帧/s final long nextFrameTime = Math.max( mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now); if (DEBUG) { Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms."); } Message msg = mHandler.obtainMessage(MSG_DO_FRAME); msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, nextFrameTime); } } }
一般情况下,我们都会走到USE_VSYNC代码块中,然后会调用
scheduleVsyncLocked();
private void scheduleVsyncLocked() { // mDisplayEventReceiver 是一个FrameDisplayEventReceiver对象。 mDisplayEventReceiver.scheduleVsync(); } private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable { @Override public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { // scheduleVsync这个最终会回调到这里。 // Ignore vsync from secondary display. // This can be problematic because the call to scheduleVsync() is a one-shot. // We need to ensure that we will still receive the vsync from the primary // display which is the one we really care about. Ideally we should schedule // vsync for a particular display. // At this time Surface Flinger won't send us vsyncs for secondary displays // but that could change in the future so let's log a message to help us remember // that we need to fix this. if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) { Log.d(TAG, "Received vsync from secondary display, but we don't support " + "this case yet. Choreographer needs a way to explicitly request " + "vsync for a specific display to ensure it doesn't lose track " + "of its scheduled vsync."); scheduleVsync(); return; } // Post the vsync event to the Handler. // The idea is to prevent incoming vsync events from completely starving // the message queue. If there are no messages in the queue with timestamps // earlier than the frame time, then the vsync event will be processed immediately. // Otherwise, messages that predate the vsync event will be handled first. long now = System.nanoTime(); if (timestampNanos > now) { Log.w(TAG, "Frame time is " + ((timestampNanos - now) * 0.000001f) + " ms in the future! Check that graphics HAL is generating vsync " + "timestamps using the correct timebase."); timestampNanos = now; } if (mHavePendingVsync) { Log.w(TAG, "Already have a pending vsync event. There should only be " + "one at a time."); } else { mHavePendingVsync = true; } // 发送消息至主线程。最终走了run()方法 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); } } public abstract class DisplayEventReceiver { /** * Schedules a single vertical sync pulse to be delivered when the next * display frame begins. */ 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);// jni最终会回调dispatchVsync()方法 } } // Called from native code. @SuppressWarnings("unused") private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) { onVsync(timestampNanos, builtInDisplayId, frame);// 回调至子类的onVsync()方法 } }
通过上述代码注释可知,我们最终会回调至
onVsync(long timestampNanos, int builtInDisplayId, int frame)继而调用
doFrame(long frameTimeNanos, int frame)。
void doFrame(long frameTimeNanos, int frame) {
final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {// 同步。只会一次一次执行。
return; // no work to do
}
// 中间这一段代码都是关于时间的计算。计算有没有跳帧之类的
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) {
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) {
Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
+ "previously skipped frame. Waiting for next vsync.");
}
scheduleVsyncLocked();
return;
}
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
}
// 这些回调都是之前注册进去的。注意顺序。 doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);// 输入/触摸事件的回调 doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);// 属性动画的回调 doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);// 绘制的回调
if (DEBUG) {
final long endNanos = System.nanoTime();
Log.d(TAG, "Frame " + frame + ": Finished, took "
+ (endNanos - startNanos) * 0.000001f + " ms, latency "
+ (startNanos - frameTimeNanos) * 0.000001f + " ms.");
}
}
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;// 这块算是对当初传进来的回调的一个封装。只是外面包了一层而已。
synchronized (mLock) {
// We use "now" to determine when callbacks become due because it's possible
// for earlier processing phases in a frame to post callbacks that should run
// in a following phase, such as an input event that causes an animation to start.
final long now = SystemClock.uptimeMillis();
// 获取之前的回调,并执行
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
if (callbacks == null) {
return;
}
mCallbacksRunning = true;
}
try {
for (CallbackRecord c = callbacks; c != null; c = c.next) {
if (DEBUG) {
Log.d(TAG, "RunCallback: type=" + callbackType
+ ", action=" + c.action + ", token=" + c.token
+ ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
}
c.run(frameTimeNanos);// 最终会执行到原Runnable的run()方法
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
}
}
这样,我们在
doFrame(long frameTimeNanos, int frame)中就会回调那3种事件,其中就有我们注册进去的重绘事件,也就回调至
doTraversal()方法了。这就是我们平常看到的方法调用栈中由
doFrame()到
doTraversal()的过程,接下来就是愉快的绘制流程了。
相关文章推荐
- Mina源码阅读笔记(七)—Mina的拦截器FilterChain
- SDL源码阅读笔记(2) video dirver的初始化及选择
- JDK 1.7源码阅读笔记(二)集合类之ArrayList
- JDK 1.7源码阅读笔记(三)集合类之LinkedList
- Mina源码阅读笔记(六)—Mina异步IO的实现IoFuture
- 非典型2D游戏引擎 Orx 源码阅读笔记(4) 用C实现的基本容器(List,HashTable,Tree)
- i.MX6qSabreLite内核源码阅读笔记-----mx6q_sabrelite_init_uart 分析
- jvm源码阅读笔记[6]-杂谈JIT中对Exception做的优化
- Vue2.0源码阅读笔记--双向绑定实现原理
- Struts2类型转换TypeConverter源码阅读笔记
- Yii源码阅读笔记 - 路由解析
- Spring framework MVC源码阅读笔记(一)
- CI框架源码阅读笔记1 - 环境准备、基本术语和框架流程
- Mina源码阅读笔记(三)-Mina的连接IoAccpetor
- Android应用层源码阅读笔记
- Three.js源码阅读笔记
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
- linux源码阅读笔记 void 指针