Android中老生常谈的ViewRootImpl的scheduleTraversals()到底做了什么?

在Android中我们知道,Activity启动完成之后,走完onResume方法之后,会进行window的添加。添加过程会调用ViewRootImpl的setView()方法,setView()方法中又会调用requestLayout()方法来请求绘制布局,接着会进入到scheduleTraversals()方法,再走到performTraversals()方法,在performTraversals()方法中,会进行测量、布局、绘制等三大流程。

除此之外,当我们使用ValueAnimator.start()、View.invalidate()时,最后也会走到ViewRootImpl的scheduleTraversals()方法,想要了解具体的,可以自行查看源码,这里就不做过多的说明了。因此,我们可以得出结论

所有UI的变化都是走到ViewRootImpl的scheduleTraversals()方法

思考这样一个问题?当调用ViewRootImpl的scheduleTraversals()方法之后,会立即就调用performTraversals()方法吗?另外,我们知道现在Android系统中,当我们接收到VSYNC信号之后才会开始绘制,那VSYNC信号又是在哪里接收的呢?带着疑问,我们展开来说。

首先来看,ViewRootImpl的scheduleTraversals()方法,代码如下:

void scheduleTraversals() {
        //设置一个成员变量,标明是否正在执行
        if (!mTraversalScheduled) {
            //标记位设置为true,避免重复执行
            mTraversalScheduled = true;
            //添加同步屏障,目的是屏蔽同步消息
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

可以看到,上面的代码中,调用mChoreographer.postCallback()函数时候,post的是一个mTraversalRunnable,我们来看下这个mTraversalRunnable是什么。

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

TraversalRunnable类定义在ViewRootImpl中,如下:

final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }

可以看到,该类实现了Runnable接口,在run()方法中,执行了doTraversal()函数,我们接着看下doTraversal()函数。

void doTraversal() {
        if (mTraversalScheduled) {
            //将在上面scheduleTraversals()方法中设置的标记为置为false
            mTraversalScheduled = false;
            //移除同步屏障(使用添加同步屏障的时候返回的mTraversalBarrier变量)
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }
            //真正开始绘制流程
            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

综上分析,我们可以得出结论,在我们调用ViewRootImpl的scheduleTraversals()方法后,并不是立即就开始执行performTraversals()的,而是需要等到使用Choreographer类的postCallback()方法post出去的Runnable回调执行run()方法的时候,才开始真正的绘制流程,即调用performTraversals()方法。

知道了大致流程,下面我们开始从源码角度去分析。

添加同步屏障

什么是同步屏障?

在Handler中,消息分为三种:同步消息、异步消息、同步屏障消息,它们三种消息都是Message,只是属性不同。

同步消息和异步消息的区别在于Message中的flags属性对应的值。可以看一下Message的源码:

/** If set message is asynchronous */
    static final int FLAG_ASYNCHRONOUS = 1 << 1;

在Message类中,有一个setAsynchronous()方法:

public void setAsynchronous(boolean async) {
        if (async) {
            flags |= FLAG_ASYNCHRONOUS;
        } else {
            flags &= ~FLAG_ASYNCHRONOUS;
        }
    }

我们可以通过该方法,将Message设置为异步消息。

除此之外,在Handler类中还有一个成员变量mAsynchronous,该变量在Handler的某一个构造函数中被赋值,默认是false。

 public Handler(@Nullable Callback callback, boolean async) {
        ......
        //这里可以通过Handler的构造函数将mAsynchronous设置为true
        mAsynchronous = async;
    }

一旦我们将Hanlder的mAsynchronous设置为true,那么在Handler的enqueueMessage方法中,就会把所有到来的消息设置为异步消息

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();
        //这里增加了判断,如果mAsynchronous为true,设置Message为异步消息
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

同步屏障消息

上面我们通过MessageQueue的postSyncBarrier方法添加一个同步屏障,具体看下代码:

public int postSyncBarrier() {
        return postSyncBarrier(SystemClock.uptimeMillis());
    }
    private int postSyncBarrier(long when) {
        synchronized (this) {
            final int token = mNextBarrierToken++;
            //注意这里,在创建Message的时候,并没有给Message设置target(Handler)属性
            final Message msg = Message.obtain();
            msg.markInUse();
            msg.when = when;
            msg.arg1 = token;
            //MessageQueue中存储的Message是一个链式结构
            Message prev = null;
            Message p = mMessages;
            //根据Message的时间进行排序,排序越靠前的消息,when属性的值越小,越早被执行
            if (when != 0) {
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
            }
            if (prev != null) { // invariant: p == prev.next
                msg.next = p;
                prev.next = msg;
            } else {
                msg.next = p;
                mMessages = msg;
            }
            return token;
        }
    }

从上述我们可以看到:

1.同步屏障消息和普通的同步异步消息的区别是,同步屏障消息没有target属性,因为同步屏障消息的作用是屏蔽同步消息从而保证异步消息优先执行的。

2.同步屏障消息和普通消息一样,也是根据时间来插入到消息队列中的适当位置,并且只会挡住它后面的同步消息的分发。

3.postSyncBarrier方法返回值是一个int类型,该数值可以用作撤销同步屏障。

那么同步屏障消息是如何拦住同步消息从而保证异步消息优先处理的呢?我们知道,Handler消息机制中所有的消息的获取都是从MessageQueue的next方法中,来看下MessageQueue的next方法:


Message next() {
        ......
        for (;;) {
            .......
            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                // target == null条件满足,说明是同步屏障消息
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    //只取异步消息,即msg.isAsynchronous为true
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
                ......
        }
    }

Choreographer的postCallback()分析

方法入参

public void postCallback(int callbackType, Runnable action, Object token) {
        postCallbackDelayed(callbackType, action, token, 0);
    }

Choreographer.CALLBACK_TRAVERSAL

通过源码可以发现,第一个参数在Choreographer类中有五个不同的值

/**
     * Callback type: Input callback.  Runs first.
     * @hide 
     */
    public static final int CALLBACK_INPUT = 0;

    /**
     * Callback type: Animation callback.  Runs before {@link #CALLBACK_INSETS_ANIMATION}.
     * @hide
     */
    @TestApi
    public static final int CALLBACK_ANIMATION = 1;

    /**
     * Callback type: Animation callback to handle inset updates. This is separate from
     * {@link #CALLBACK_ANIMATION} as we need to "gather" all inset animation updates via
     * {@link WindowInsetsAnimationController#changeInsets} for multiple ongoing animations but then
     * update the whole view system with a single callback to {@link View#dispatchWindowInsetsAnimationProgress}
     * that contains all the combined updated insets.
     * <p>
     * Both input and animation may change insets, so we need to run this after these callbacks, but
     * before traversals.
     * <p>
     * Runs before traversals.
     * @hide
     */
    public static final int CALLBACK_INSETS_ANIMATION = 2;

    /**
     * Callback type: Traversal callback.  Handles layout and draw.  Runs
     * after all other asynchronous messages have been handled.
     * @hide
     */
    public static final int CALLBACK_TRAVERSAL = 3;

    /**
     * Callback type: Commit callback.  Handles post-draw operations for the frame.
     * Runs after traversal completes.  The {@link #getFrameTime() frame time} reported
     * during this callback may be updated to reflect delays that occurred while
     * traversals were in progress in case heavy layout operations caused some frames
     * to be skipped.  The frame time reported during this callback provides a better
     * estimate of the start time of the frame in which animations (and other updates
     * to the view hierarchy state) actually took effect.
     * @hide
     */
    public static final int CALLBACK_COMMIT = 4;

上述注释解释的很清楚:

事件值 解释说明
CALLBACK_INPUT 输入事件,第一个执行
CALLBACK_ANIMATION 动画,在CALLBACK_INSETS_ANIMATION前执行
CALLBACK_INSETS_ANIMATION 输入和动画之后,TRAVERSAL之前
CALLBACK_TRAVERSAL 处理布局和绘制,运行在其他异步消息之后
CALLBACK_COMMIT 提交,最后执行


第二个参数需要的是一个Runnable

第三个参数为Object token

我们在ViewRootImpl中调用scheduleTraversals()方法中:

mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

第一个参数传入的是CALLBACK_TRAVERSAL(布局和绘制)。

第二个参数传入的是mTraversalRunnable,上面已经说过,就是一个实现了Runnable接口的TraversalRunnable类。

第三个参数传入的是null。

接着往下分析,可以看到在Choreographer类中又调用了

 //注意这里传入的delayMillis是0
 postCallbackDelayed(callbackType, action, token, 0);

接着看该方法:

public void postCallbackDelayed(int callbackType,
            Runnable action, Object token, long delayMillis) {
        //判断传入的Runnable是否为null,如果为null,抛异常
        if (action == null) {
            throw new IllegalArgumentException("action must not be null");
        }
        //判断传入的callbackType是否正常(是否满足该类中定义的五个值)
        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) {
            //由于传入的delayMillis是0,所以dueTime == now
            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);
            }
        }
    }

上述代码中,mCallbackQueues是Choreographer类中的一个数组,初始化是在Choreographer类的构造方法中:

mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
        for (int i = 0; i <= CALLBACK_LAST; i++) {
            mCallbackQueues[i] = new CallbackQueue();
        }

mCallbackQueues的长度是5,并且为数组中的每一个元素都新建了一个CallbackQueue。看下CallbackQueue,CallbackQueue是Choreographer类的一个内部类:

private final class CallbackQueue {
        private CallbackRecord mHead;

        public boolean hasDueCallbacksLocked(long now) {
            return mHead != null && mHead.dueTime <= now;
        }

        public CallbackRecord extractDueCallbacksLocked(long now) {
            ......
        }

        @UnsupportedAppUsage
        public void addCallbackLocked(long dueTime, Object action, Object token) {
            ......
        }

        public void removeCallbacksLocked(Object action, Object token) {
            ......
        }
    }

可以看到,在CallbackQueue中存储的是CallbackRecord,看下CallbackRecord类:

private static final class CallbackRecord {
        public CallbackRecord next;
        public long dueTime;
        public Object action; // Runnable or FrameCallback
        public Object token;

        @UnsupportedAppUsage
        public void run(long frameTimeNanos) {
            if (token == FRAME_CALLBACK_TOKEN) {
                ((FrameCallback)action).doFrame(frameTimeNanos);
            } else {
                ((Runnable)action).run();
            }
        }
    }

CallbackRecord类中有一个成员变量是next,指向的是下一个CallbackRecord,因此在CallbackQueue中存储的是一个链式结构的CallbackRecord。注意这里的run()方法,下面会用到。

回到postCallbackDelayedInternal()方法中继续看,我们现在传入的delayMillis是0,因此dueTime == now,所以会执行scheduleFrameLocked(now)方法。那如果走到else呢?答案是依然会执行scheduleFrameLocked(now)方法。

简单看下:

Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);

如果delayMillis不是0,那么会使用mHandler发送一个下次,该Message的what是 MSG_DO_SCHEDULE_CALLBACK 。mHandler指向的是Choreographer类中的FrameHandler,我们看下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:
                    doScheduleCallback(msg.arg1);
                    break;
            }
        }
    }

当 msg.what = MSG_DO_SCHEDULE_CALLBACK 的时候,执行的是doScheduleCallback(msg.arg1),看下该方法:

void doScheduleCallback(int callbackType) {
        synchronized (mLock) {
            if (!mFrameScheduled) {
                final long now = SystemClock.uptimeMillis();
                if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                    scheduleFrameLocked(now);
                }
            }
        }
    }

可以看到这里依然会走到scheduleFrameLocked(now)方法中。至于判断条件,有兴趣的可以自己去分析下。

接下来来看一下scheduleFrameLocked(now)方法:

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);
            }
        }
    }

可以看到,方法进来之后,先判断了mFrameScheduled是否为true,此时不是true,因此进入方法体中,并且将mFrameScheduled设置为true。紧接着判断USE_VSYNC是否为true,这个参数指的是是否开启了VSYNC,我们通过查资料可以知道在Android 4.1 之后默认开始了VSYNC,因此如果当前Android 系统是4.1以后,那么会走if里面的逻辑,反之则会调用else里面的逻辑。这里稍微看下4.1之前的逻辑,即不使用VSYNC信号,则会直接发送一个 what = MSG_DO_FRAME的Message,通过上面FrameHandler的代码可以知道,会调用doFrame方法。doFrame方法我们下面再分析。这里只要知道,如果没有使用VSYNC信号,则会直接调用doFrame方法即可。

如果使用VSYNC信号,即进入if中,这里会判断,isRunningOnLooperThreadLocked(),该方法内部根据Looper判断会否在原线程。

 private boolean isRunningOnLooperThreadLocked() {
        return Looper.myLooper() == mLooper;
    }

如果是在原线程,则调用scheduleVsyncLocked()方法,否则发送一个 what = MSG_DO_SCHEDULE_VSYNC 的Message,继续看FrameHandler的代码发现,如果what = MSG_DO_SCHEDULE_VSYNC,会调用doScheduleVsync()方法

void doScheduleVsync() {
        synchronized (mLock) {
            if (mFrameScheduled) {
                scheduleVsyncLocked();
            }
        }
    }

在该方法中,因为在scheduleFrameLocked()方法中我们已经将mFrameScheduled设置为true,因此会执行scheduleVsyncLocked()方法。

到这里我们已经可以看到FrameHandler的作用了:发送异步消息。因为我们之前已经设置了同步屏障,因此该异步消息会被执行。同时,如果任务是延迟的任务,发送延迟消息。如果不在原线程,通过mHandlder发送消息到原线程.如果没有开启VSYNC的直接调用doFramen方法。

接着来看下scheduleVsyncLocked()方法。

private void scheduleVsyncLocked() {
        mDisplayEventReceiver.scheduleVsync();
    }

mDisplayEventReceiver是FrameDisplayEventReceiver的实例,我们看下FrameDisplayEventReceiver。

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, long physicalDisplayId, int frame) {
            ......
        }

        @Override
        public void run() {
            ......
        }
    }

可以看到,FrameDisplayEventReceiver继承自DisplayEventReceiver,并实现了Runnable接口。实现了两个方法,onVsync()和run(),其中onVsync方法来自DisplayEventReceiver,run()方法来自Runnable接口。mDisplayEventReceiver是在Choreographer的构造方法中创建出来的,找到对应的代码:

 private Choreographer(Looper looper, int vsyncSource) {
        mLooper = looper;
        mHandler = new FrameHandler(looper);
        mDisplayEventReceiver = USE_VSYNC
                ? new FrameDisplayEventReceiver(looper, vsyncSource)
                : null;
        ......
    }

可以看到,如果没有使用VSYNC,则mDisplayEventReceiver为null,反之则创建。在创建的时候,传入了当前的looper。在该类中没有找到scheduleVsync()方法,那我们就去父类中去找,先看下父类的构造方法

public DisplayEventReceiver(Looper looper, int vsyncSource) {
        if (looper == null) {
            throw new IllegalArgumentException("looper must not be null");
        }

        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
                vsyncSource);

        mCloseGuard.open("dispose");
    }

可以看到,在父类的构造方法中,先判断了looper是否为null。然后从looper中获取到MessageQueue赋值给mMessageQueue,然后调用了一个native的方法,并将返回值赋值给了mReceiverPtr。我们看下父类的scheduleVsync()方法。

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);
        }
    }

在该方法中,先判断了mReceiverPtr是否为0。这里应该就是在构造方法中,如果调用nativeInit方法成功的话,值就不是0。因此如果mReceiverPtr不是0,会调用nativeScheduleVsync(mReceiverPtr)。该方法也是一个native方法,这里就不往下看了,我们只需要知道VSYNC信号的接收回调是onVsync()方法。因此我们继续看onVsync方法。在DisplayEventReceiver中,onVsync是一个空实现,因此我们回到FrameDisplayEventReceiver类的onVsync方法

public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
            ......
            mTimestampNanos = timestampNanos;
            mFrame = frame;
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
        }

上面的直接省略,我们看下通过mHandler发送消息,可以看到,这里创建Message消息的时候,传入的是this,因为FrameDisplayEventReceiver实现了Runnable接口,因此在handler处理消息的时候回调run方法,在run方法中,调用了doFramen方法。另外,这里调用了msg.setAsynchronous(true),通过handler发送到MessageQueue中的是一个异步消息,我们前面已经post了一个同步屏障,因此该异步消息会被调用。
注意,在上面我们提到了,在Android 4.1之前,也会走到doFramen方法中去。
下面来看下doFrame方法

void doFrame(long frameTimeNanos, int frame) {
        final long startNanos;
        synchronized (mLock) {
        ......
        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中依次执行了doCallbacks方法,传入的类型是我们上面提到的Choreographer类中定义好的五种类型。看下doCallbacks方法:

 void doCallbacks(int callbackType, long frameTimeNanos) {
            CallbackRecord callbacks;
            synchronized (mLock) {
                callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                            now / TimeUtils.NANOS_PER_MS);
                    if (callbacks == null) {
                        return;
                    }
                ......
                for (CallbackRecord c = callbacks; c != null; c = c.next) {
                    if (DEBUG_FRAMES) {
                        Log.d(TAG, "RunCallback: type=" + callbackType
                                + ", action=" + c.action + ", token=" + c.token
                                + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                    }
                    c.run(frameTimeNanos);
                }
            } finally {
                synchronized (mLock) {
                    mCallbacksRunning = false;
                    do {
                        final CallbackRecord next = callbacks.next;
                        recycleCallbackLocked(callbacks);
                        callbacks = next;
                    } while (callbacks != null);
                }
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
    }

可以看到,首先根据指定的任务类型,从mCallbackQueues中查找需要执行的CallbackRecord,如果是null,直接return了。紧接着,遍历执行CallbackRecord中的所有任务,回调CallbackRecord的run 方法。

public void run(long frameTimeNanos) {
            if (token == FRAME_CALLBACK_TOKEN) {
                ((FrameCallback)action).doFrame(frameTimeNanos);
            } else {
                ((Runnable)action).run();
            }
        }

因为我们在上面往CallbackRecord中add任务的时候,传入的token是null,所以这里直接走到了action.run()方法,而action是前面提到的TraversalRunnable,所以直接调用了TraversalRunnable类的run方法,然后调用了doTraversal(),在doTraversal()方法中,开始真正的绘制流程。看下doTraversal方法:

void doTraversal() {
        if (mTraversalScheduled) {
            //标记位设为false
            mTraversalScheduled = false;
            //从MessageQueue中移除同步屏障消息
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }
            //真正开始绘制流程
            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

在调用performTraversals之前,调用了mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier),在这里就把之前我们添加的同步屏障从MessageQueue中移除,从而使MesssageQueue中next()方法可以正常取到同步消息。

那么什么时候token == FRAME_CALLBACK_TOKEN成立呢?我们在Choregrapher类中查找FRAME_CALLBACK_TOKEN发现,在调用postFrameCallback的时候,会调用postFrameCallbackDelayed

public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
        if (callback == null) {
            throw new IllegalArgumentException("callback must not be null");
        }

        postCallbackDelayedInternal(CALLBACK_ANIMATION,
                callback, FRAME_CALLBACK_TOKEN, delayMillis);
    }

在这里传入了FRAME_CALLBACK_TOKEN。那么该方法的执行流程呢?可以看到,在这个方法中也是调用到了postCallbackDelayedInternal方法,只不过传入了token参数。并且这里传入的是action是FrameCallback,FrameCallback中只有一个doFrame方法。postFrameCallback通常情况下用来计算丢帧情况。
使用一张图来梳理一下在整个Choreographer中的流程

在此感谢下面参考文章的作者,在没有看到该作者的文章之前,也看过这个绘制流程的源码,但总是看不进去,看一点忘一点。后来看到这篇文章之后,结合文章中所介绍的内容再去看源码,静下心来,慢慢的就看明白了,特此感谢。其实我们学习就是这样了,找到一个自己喜欢的学习方法,学习就会变得有乐趣。想要成长起来,源码是绕不开的,通过看源码、理解源码能够使我们加深对于整个Android系统的理解,从而让自己更上一层楼。

参考文章https://juejin.cn/post/6863756420380196877

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容