Choreographer 源码阅读笔记

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()的过程,接下来就是愉快的绘制流程了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值