一、View#invalidate开始分析
1.1、View.invalidate()会发起一次View绘制
-
(1)分析View.invalidate()源码如下:
public void invalidate() { invalidate(true); } public void invalidate(boolean invalidateCache) { invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); } void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,boolean fullInvalidate) { ... final AttachInfo ai = mAttachInfo; final ViewParent p = mParent; if (p != null && ai != null && l < r && t < b) { final Rect damage = ai.mTmpInvalRect; damage.set(l, t, r, b); //调用了ViewGroup的invalidateChild方法 p.invalidateChild(this, damage); } ... }
-
(2)这里调用到了ViewGroup的方法,ViewGroup#invalidateChild()
public final void invalidateChild(View child, final Rect dirty) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null && attachInfo.mHardwareAccelerated) { // HW accelerated fast path onDescendantInvalidated(child, child); return; } ViewParent parent = this; if (attachInfo != null) { ... do { View view = null; if (parent instanceof View) { view = (View) parent; } ... // 通过do-while // 递归调用父的invalidateChildInParent,直到最顶层的View为止 // 也就是通过递归的方式找父 // 因为只有找到父,才可以测量、布局、绘制整个view parent = parent.invalidateChildInParent(location, dirty); ... } while (parent != null); } }
-
其实,从View层面最终肯定会找到DecorView,但是顺着DecorView的创建以及添加到Window的时机,可以发现在->ViewRootImpl#setView()存在view.assignParent(this)->View#assignParent()这个调用链儿,
-
所以在ViewGroup找的这个parent就是DecorView的父,就是ViewRootImpl
1.2、分析ViewRootImpl#invalidateChildInParent()
-
(1)分析ViewRootImpl#invalidateChildInParent()
public ViewParent invalidateChildInParent(int[] location, Rect dirty) { checkThread(); if (dirty == null) { //1.这个地方会调用invalidate(),里边会调用scheduleTraversals() invalidate(); return null; } else if (dirty.isEmpty() && !mIsAnimating) { return null; } ... // 2.这个地方最终也会调用scheduleTraversals() invalidateRectOnScreen(dirty); return null; }
-
所以不管走到1还是2,最红都会执行scheduleTraversals(),这个流程与View.requestLayout不谋而合。
-
(2)分析ViewRootImpl#scheduleTraversals
void scheduleTraversals() { //1.防止多次调用,一个vsync时期内,没必须要多次调用 if (!mTraversalScheduled) { mTraversalScheduled = true; //2.发送一个同步屏障,保证handler先处理异步消息 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); //3.通过编舞者发送一个runnable, mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); ... } }
二、Choreographer编舞者
2.1、mChoreographer什么时候初始化
-
在ViewRootImpl的构造方法中初始化好了,mChoreographer = Choreographer.getInstance();
-
mChoreographer是保存在ThreadLocal中的线程私有的变量,所以这个mChoreographer是跟随线程的
-
Choreographer源代码分析:
/** * 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. */ public static Choreographer getInstance() { return sThreadInstance.get(); } // 1.sThreadInstance是一个ThreadLocal<Choreographer>对象,线程私有的 private Choreographer(Looper looper, int vsyncSource) { mLooper = looper; mHandler = new FrameHandler(looper); // FrameDisplayEventReceiver是vsync事件接收器,是Choreographer的内部类 // 它的父类是DisplayEventReceiver mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper, vsyncSource) : null; mLastFrameTimeNanos = Long.MIN_VALUE; // 一帧的事件,60fts就是1s刷新60帧,也就是一帧需要16.7ms mFrameIntervalNanos = (long)(1000000000 / getRefreshRate()); //回调队列 mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1]; for (int i = 0; i <= CALLBACK_LAST; i++) { mCallbackQueues[i] = new CallbackQueue(); } }
2.2、mTraversalRunnable是什么
-
mTraversalRunnable就是一个runnable,将来要执行的run方法内部的方法
final class TraversalRunnable implements Runnable { @Override public void run() { doTraversal(); } } final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
2.3、mChoreographer是如何发送任务,以及任务是如何被调度执行的
-
vsync是一个由硬件发出来的信号,Choreographer主要负责监听这个信号,每当信号来临时,统一开始绘制流程
-
继续分析mChoreographer.postCallback
// 从ViewRootImpl的scheduleTraversals中开始 mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); 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) { ... postCallbackDelayedInternal(callbackType, action, token, delayMillis); } private void postCallbackDelayedInternal(int callbackType,bject action, Object token, long delayMillis) { synchronized (mLock) { final long now = SystemClock.uptimeMillis(); final long dueTime = now + delayMillis; // 将mTraversalRunnable 加入队列 mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token); if (dueTime <= now) { // 因为delayMillis=0,这里会走进去 scheduleFrameLocked(now); } else { //延迟执行 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action); msg.arg1 = callbackType; // 发送一个异步消息 msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, dueTime); } } }
-
整个postCallback的调用链就是这样的
Choreographer#postCallback
->postCallbackDelayed
->postCallbackDelayedInternal
->scheduleFrameLocked
->scheduleVsyncLocked
->DisplayEventReceiver.scheduleVsync();
-
最终调到DisplayEventReceiver中
2.4、收到底层信号后做了什么
(1)从DisplayEventReceiver#dispatchVsync开始分析
// Called from native code.
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
onVsync(timestampNanos, physicalDisplayId, frame);
}
-
Choreographer.postCallback()
方法通过DisplayEventReceiver.nativeScheduleVsync()
方法向系统底层注册了下一次vsync
信号的监听。 -
当下一次
vsync
来临时,系统会回调其dispatchVsync()
方法,因为父类从DisplayEventReceiver中onVsync是个空方法,最终回调FrameDisplayEventReceiver.onVsync()
方法。 -
FrameDisplayEventReceiver.onVsync()
方法中取出之前提交的mTraversalRunnable
并执行。 (2)看下FrameDisplayEventReceiver#onVsync()做了什么@Override public void onVsync(long timestampNanos, long physicalDisplayId, int frame) { // 发送 vsync event to the Handler. // 如果这个时候,消息队列中没有比当前帧更早的消息,这个帧消息会立刻执行 // 否则早已当前帧消息的消息会先执行 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; // 1.timestampNanos是vsync回调的时间,单位是纳秒,不能比now大 } if (mHavePendingVsync) { Log.w(TAG, "Already have a pending vsync event. There should only be " + "one at a time."); } else { mHavePendingVsync = true; } //2. 代码执行到这里的vsync信号已经发生,而且上面1处到这行代码也需要耗时,所以此时timestampNanos一定是<now的,这就确保了这一帧的消息一定会插入到MQ的队首,从而优先执行 mTimestampNanos = timestampNanos; mFrame = frame; // 此处设置callback是this,所以会回调本类的run方法 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); }
-
一定要搞清楚为什么当前帧的消息会被插入到MQ的队首,看注释2 (3)分析onFrame()
void doFrame(long frameTimeNanos, int frame) { final long startNanos; synchronized (mLock) { ...
//1.frameTimeNanos是vsync信号回调时间 long intendedFrameTimeNanos = frameTimeNanos; //2. startNanos是当前时间 startNanos = System.nanoTime(); //3. 2和1相减,就是主线程的耗时时间 final long jitterNanos = startNanos - frameTimeNanos; //mFrameIntervalNanos是一帧的时间 if (jitterNanos >= mFrameIntervalNanos) { final long skippedFrames = jitterNanos / mFrameIntervalNanos; if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { //3.掉帧30帧,就会出现常见的log,在这个地方 Log.i(TAG, "Skipped " + skippedFrames + " frames! " + "The application may be doing too much work on its main thread."); } } } try { // doCallbacks开始执行回调,根据对应的CallbackType,找到对应的CallbackRecord对象 // CallbackType只有四种,CALLBACK_INPUT,CALLBACK_ANIMATION,CALLBACK_TRAVERSAL,CALLBACK_COMMIT 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); }
}