Choreographer原理

Choreographer启动流程

在Activity启动过程,执行完onResume后,会调用Activity.makeVisible(),然后再调用到addView(), 层层调用会进入如下方法:

public ViewRootImpl(Context context, Display display) {
    ...
    //获取Choreographer实例
    mChoreographer = Choreographer.getInstance();
    ...
}

getInstance()

//frameworks/base/core/java/android/view/Choreographer.java
public static Choreographer getInstance() {
    return sThreadInstance.get();
}
    // Thread local storage for the choreographer.
private static final ThreadLocal<Choreographer> sThreadInstance =
        new ThreadLocal<Choreographer>() {
    @Override
    protected Choreographer initialValue() {
        //获取当前线程Looper
        Looper looper = Looper.myLooper();
        if (looper == null) {
            throw new IllegalStateException("The current thread must have a looper!");
        }
        Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
        if (looper == Looper.getMainLooper()) {
            mMainInstance = choreographer;
        }
        return choreographer;
    }
};

创建Choreographer

创建FrameHandler

postCallback

postCallbackDelayedInternal

创建FrameDisplayEventReceiver

DisplayEventReceiver

nativeInit

创建NativeDisplayEventReceiver

NativeDisplayEventReceiver继承于LooperCallback对象,此处mReceiverWeakGlobal记录的是Java层 DisplayEventReceiver对象的全局引用。

initialize

DisplayEventDispatcher继承LooperCallback

监听mReceiver的所获取的文件句柄,一旦有数据到来,则回调this(此处NativeDisplayEventReceiver)中所复写LooperCallback对象的 handleEvent。

Vysnc回调流程

handleEvent

processPendingEvents

遍历所有的事件,当有多个VSync事件到来,则只关注最近一次的事件。

dispatchVsync

此处调用到Java层的DisplayEventReceiver对象的dispatchVsync()方法,接下来进入Java层。

Choreographer对象实例化的过程,创建的对象是DisplayEventReceiver子类 FrameDisplayEventReceiver对象,接下来进入该对象。

onVsync

可见onVsync()过程是通过FrameHandler向主线程Looper发送了一个自带callback的消息,此处callback为FrameDisplayEventReceiver。 当主线程Looper执行到该消息时,则调用FrameDisplayEventReceiver.run()方法.

run()

doFrame()

此处frameTimeNanos是底层VSYNC信号到达的时间戳。

  1. 每调用一次scheduleFrameLocked(),则mFrameScheduled=true,能执行一次doFrame()操作,执行完doFrame()并设置mFrameScheduled=false;

  2. 最终有4个回调类别,如下所示:

    • INPUT:输入事件

    • ANIMATION:动画

    • TRAVERSAL:窗口刷新,执行measure/layout/draw操作

    • COMMIT:遍历完成的提交操作,用来修正动画启动时间

doCallbacks

该方法主要功能:

  • 从队列头mHead查找CallbackRecord对象,当队列头部的callbacks对象为空或者执行时间还没到达,则直接返回;

  • 开始执行相应回调的run()方法;

  • 回收callbacks,加入对象池mCallbackPool,就是说callback一旦执行完成,则会被回收。

CallbackRecord

这里的回调方法run()有两种执行情况:

  • 当token的数据类型为FRAME_CALLBACK_TOKEN,则执行该对象的doFrame()方法;

  • 当token为其他类型,则执行该对象的run()方法。

那么需要的场景便是由WMS调用scheduleAnimationLocked()方法来设置mFrameScheduled=true来触发动画, 接下来说说动画控制的过程。

动画显示过程

参考

最后更新于