Choreographer 翩翩起舞

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

    /**
     * Callback type: Animation callback.  Runs before traversals.
     * @hide
     */
    public static final int CALLBACK_ANIMATION = 1;

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

    private static final int CALLBACK_LAST = CALLBACK_TRAVERSAL;

Choreographer, 黄油计划引入的协调器,实现了帧(就是Frame,因为有了垂直同步,所以可能Frame_callback是定期的)同步的功能, 负责同意协调所有的task的运行。

Choreographer 所支持的三种Task, 运行顺序: input > animation > traversal.

Choreographer 的getInstance() 返回的是 ThreadLocal的实例, 每个线程都有自己的Choreographer, 并且Choreographer使用的handler所依附也是该线程:

可以看到 Looper.myLooper()

    // Thread local storage for the choreographer.
    private static final ThreadLocal sThreadInstance =
            new ThreadLocal() {
        @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);
        }
    };

private Choreographer(Looper looper) {         mLooper = looper;         mHandler = new FrameHandler(looper);

.....................

}


FrameHandler 实现了自己的handleMessage:

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,处理的逻辑是不一样的:

doScheduleVsync() 和 doScheduleCallback()都没有真正的干活,

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

比如doScheduleCallback: 先检查有没有Frame的CallBack已经被schedue了<如果有的话,在不久这些被post进来的task就可以被执行了,不需要再schedule一次>,如果没有,再看看当前的callBackQueue的第一个callback是否已经到期要执行.

如果到期要执行,那么就schedule一个 Frame的Callback:

    private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
            mFrameScheduled = true;
           如果使用了V同步: 
           if (USE_VSYNC) {
                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.
           如果当前线程就是该Choreographer所属的线程 
           if (isRunningOnLooperThreadLocked()) {
                  直接schedule一个V同步.
                  scheduleVsyncLocked();
                做的事情:
                                 mDisplayEventReceiver.scheduleVsync();
>
} else { Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); msg.setAsynchronous(true); mHandler.sendMessageAtFrontOfQueue(msg); } } else {
否则就自己计算出下一个Frame的时间,然后send一个MSG_DO_FRAME的message:
final long nextFrameTime = Math.max( mLastFrameTimeNanos / 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是异步的,不依赖严格的先后顺序.
  msg.setAsynchronous(true); mHandler.sendMessageAtTime(msg, nextFrameTime); } } }

 上面的FrameDisplayEventReceiver是一个实现了Runnable继承DisplayEventReceiver的类,其scheduleVsync(): 
  

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

    onVsync()是收到了Vsync pulse之后的响应:
    /**
     * Called when a vertical sync pulse is received.
     * The recipient should render a frame and then call {@link #scheduleVsync}
     * to schedule the next vertical sync pulse.
     *
     * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()}
     * timebase.
     * @param builtInDisplayId The surface flinger built-in display id such as
     * {@link SurfaceControl#BUILT_IN_DISPLAY_ID_MAIN}.
     * @param frame The frame number.  Increases by one for each vertical sync interval.
     */
    public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
    }


注意注释:
     * Schedules a single vertical sync pulse to be delivered when the next
     * display frame begins.

而Vsync里传递来的timestampNanos,就是本次pulse的时间戳。

而FrameDisplayEventReceiver的onVsync()函数做的事情是将作为runnable的自己send到所处的线程中去,注意是sendMessageAtTime,这里的时间是

这样计算的,如果timestampNanos > now, 那么timestampNanos = now.

Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, timestampNanos / NANOS_PER_MS);

FrameDisplayEventReceiver的run函数则是直接执行了doFrame():

而doFrame()函数才是真正的做了很多工作:

    void doFrame(long frameTimeNanos, int frame) {
        final long startNanos;
        synchronized (mLock) {
            如果没有schedule过一个FrameCallBack,直接返回.mFrameScheduled只有在scheduleFrameLocked()才会是true
            if (!mFrameScheduled) {
                return; // no work to do
            }

            startNanos = System.nanoTime();
            计算一下抖动延迟:startNanos 是当前的时间,而frameTimeNanos是该Frame计划开始的时间
            final long jitterNanos = startNanos - frameTimeNanos;
            如果抖动延迟超过了某个阈值 
            if (jitterNanos >= mFrameIntervalNanos) {
               大概计算一下跳帧的严重程度 
               final long skippedFrames = jitterNanos / mFrameIntervalNanos;
                如果跳帧跳的不能忍了,警告一下,是不是UI线程的工作太多了.
                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.");
                }
                重新规划一下该Frame开始的时间
                frameTimeNanos = startNanos - lastFrameOffset;
            }

           如果这一帧要开始的时间比上一帧开始的时间都晚,那么直接跳过此次,等待下一次的Vsync来触发了. 
           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;
            }
            
            这一帧开始了,那么就没有被schedule的帧了
            mFrameScheduled = false;
            更新上一帧开始的时间
            mLastFrameTimeNanos = frameTimeNanos;
        }
        
        这时候才开始依次执行之前post给自己的各种Task,注意执行的顺序就是最开始说的顺序:
        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.");
        }
    }

doCallbacks函数做的事情就简单了,就是把相应Task type的mCallbackQueues里已经到期的所有callBack执行一遍.


postCallbackDelayedInternal负责把MSG_DO_SCHEDULE_CALLBACK的Task, post到该Choreographer实例所属线程的handler中, 通过Message的形式,这个函数其实也是是view的requestLayout等操作,最终使ViewRootImpl调用的:

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

        synchronized (mLock) {
            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);
            }
        }
    }

关于这个类注释说的也很清晰了:

/**
 * Coordinates the timing of animations, input and drawing.
 * 

* The choreographer receives timing pulses (such as vertical synchronization) * from the display subsystem then schedules work to occur as part of rendering * the next display frame. *

* Applications typically interact with the choreographer indirectly using * higher level abstractions in the animation framework or the view hierarchy. * Here are some examples of things you can do using the higher-level APIs. *

*
    *
  • To post an animation to be processed on a regular time basis synchronized with * display frame rendering, use {@link android.animation.ValueAnimator#start}.
  • *
  • To post a {@link Runnable} to be invoked once at the beginning of the next display * frame, use {@link View#postOnAnimation}.
  • *
  • To post a {@link Runnable} to be invoked once at the beginning of the next display * frame after a delay, use {@link View#postOnAnimationDelayed}.
  • *
  • To post a call to {@link View#invalidate()} to occur once at the beginning of the * next display frame, use {@link View#postInvalidateOnAnimation()} or * {@link View#postInvalidateOnAnimation(int, int, int, int)}.
  • *
  • To ensure that the contents of a {@link View} scroll smoothly and are drawn in * sync with display frame rendering, do nothing. This already happens automatically. * {@link View#onDraw} will be called at the appropriate time.
  • *
*

* However, there are a few cases where you might want to use the functions of the * choreographer directly in your application. Here are some examples. *

*
    *
  • If your application does its rendering in a different thread, possibly using GL, * or does not use the animation framework or view hierarchy at all * and you want to ensure that it is appropriately synchronized with the display, then use * {@link Choreographer#postFrameCallback}.
  • *
  • ... and that's about it.
  • *
*

* Each {@link Looper} thread has its own choreographer. Other threads can * post callbacks to run on the choreographer but they will run on the {@link Looper} * to which the choreographer belongs. *

*/

Choreographer应该是由两种触发来运行doFrame的,一种可能是系统通过Vsync触发的<猜的,不一定,因为scheduleFrameLocked是一个private函数>,另外一种就是通过postCallback()触发了一个scheduleVsync,

最终还是一个Vsync触发了doFrame,来进行操作的. 不过如果之前已经有一个Frame将要执行了,那么就不需要再schedule一个,直接等待这个Frame的来临即可.


From:http://www.360doc.com/content/14/0329/00/10366845_364576441.shtml

所有的图像显示输出都是由时钟驱动的,这个驱动信号称为VSYNC。这个名词来源于模拟电视时代,在那个年代,因为带宽的限制,每一帧图像都有分成两次传输,先扫描偶数行(也称偶场)传输,再回到头部扫描奇数行(奇场),扫描之前,发送一个VSYNC同步信号,用于标识这个这是一场的开始。场频,也就是VSYNC 频率决定了帧率(场频/2). 在现在的数字传输中,已经没有了场的概念,但VSYNC这一概念得于保持下来,代表了图像的刷新频率,意味着收到VSYNC信号后,我们必须将新的一帧进行显示。

VSYNC一般由硬件产生,也可以由软件产生(如果够准确的话),Android 中VSYNC来着于HWComposer,接收者没错,就是Choreographer。Choreographer英文意思是编舞者,跳舞很讲究节奏不是吗,必须要踩准点。Choreographer 就是用来帮助Android的动画,输入,还是显示刷新按照固定节奏来完成工作的。


从图中我们可以看到, Choreographer 是ViewRootImpl 创建的(Choreographer是一个sigleton类,第一个访问它的ViewRootImpl创建它),它拥有一个Receiver, 用来接收外部传入的Event,它还有一个Callback Queue, 里面存放着若干个CallbackRecord, 还有一个FrameHandler,用来handleMessage, 最后,它还跟Looper有引用关系。再看看下面这张时序图,一切就清楚了,


首先Looper调用loop() 后,线程进入进入睡眠,直到收到一个消息。Looper也支持addFd()方法,这样如果某个fd上发生了IO操作(read/write), 它也会从睡眠中醒来。Choreographer的实现用到了这两种方式,首先他通过某种方式获取到SurfaceFlinger 进程提供的fd,然后将其交给Looper进行监听,只要SurfaceFlinger往这个fd写入VSync事件,looper便会唤醒。Lopper唤醒后,会执行onVsync()时间,这里面没有做太多事情,而是调用Handler接口 sendMessageAtTime() 往消息队列里又送了一个消息。这个消息最终调到了Handler (实际是FrameHandler)的handleCallback来完成上层安排的工作。为什么要绕这么大个圈?为什么不在onVSync里直接handleCallback()? 毕竟onVSync 和 handleCallback() 都在一个线程里。这是因为MessageQueue 不光接收来自SurfaceFlinger 的VSync 事件,还有来自上层的控制消息。VSync的处理是相当频繁的,如果不将VSync信号送人MessageQueue进行排队,MessageQueue里的事件就有可能得不到及时处理,严重的话会导致溢出。当然了,如果因为VSync信号排队而导致处理延迟,这就是设计的问题了,这也是为什么Android文档里反复强调在Activity的onXXX()里不要做太耗时的工作,因为这些回调函数和Choreographer运行在同一个线程里,这个线程就是所谓的UI线程。

言归正传,继续往前,VSync事件最终在doFrame()里调了三次doCallbacks()来完成不同的功能, 分别处理用户输入事件,动画刷新(动画就是定时更新的图片), 最后执行performTraversals(),这个函数里面主要是检查当前窗口当前状态,比如说是否依然可见,尺寸,方向,布局是否发生改变(可能是由前面的用户输入触发的),分别调用performMeasure(), performLayout, performDraw()完成测量,布局和绘制工作。

你可能感兴趣的:(Android,Animation,项目经历,Android,View,Android,Schedule,Android)