Android Choreographer

本文详细介绍了Android中的Choreographer类,用于协调动画、输入和绘图的时间,以及如何利用Choreographer进行性能监控,解决卡顿和丢帧问题。通过分析Choreographer的源码,阐述了其工作原理,包括如何接收VSYNC信号、如何调度帧渲染,以及与View绘制的关联。此外,还讨论了Choreographer在实际应用中的场景,如自定义FPSMonitor来监控App性能。
摘要由CSDN通过智能技术生成

引言

之前其实并未关注过Choreographer,在一次调试App demo的过程中,偶然发现出现了一条这样的日志:

I/Choreographer: Skipped 1201 frames! The application may be doing too much work on its main thread.

这是一条系统日志,意思很明确:主线程的工作可能过多,导致了掉帧。突然发现Choreographer很有用,可以用来监控App性能、卡顿、帧率等,于是决定花点时间学习一下。

简介

Choreographer类位于android.view包下,是一个final类,是从Android 4.1(API level=16)开始加入的一种机制。Choreographer字面意为“编舞、编导”,从官方文档可以得到以下重要信息:

  • 协调动画、输入和绘图的时间。
  • Choreographer从显示子系统接收定时脉冲,如VSYNC信号,然后调度安排下一帧的渲染工作。
  • 应用程序一般不与Choreographer直接交互,而是在动画框架或视图层次架构中使用更高层的抽象API来调用。
  • 也有一些在App中直接使用Choreographer的场景,如App在不同的线程进行渲染,可能使用GL,没有使用动画框架或视图层次架构,当需要确保能够和显示同步的时候,可以调用Choreographer的 postFrameCallback(Choreographer.FrameCallback)方法。
  • 每一个Looper线程都有自己的Choreographer,其他线程发送的回调只能运行在对应Choreographer所属的Looper线程上。

源码分析

Choreographer源码基于Android 7.1.1,不同版本源码可能有所不同。

  1. 类声明

    public final class Choreographer{
         }
  2. 构造函数

    private Choreographer(Looper looper) {
       mLooper = looper;
       mHandler = new FrameHandler(looper);
       // 根据是否使用了VSYNC来创建一个FrameDisplayEventReceiver对象
       mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
       mLastFrameTimeNanos = Long.MIN_VALUE;
       // 1秒=1000毫秒=1000000微秒=1000000000纳秒,mFrameIntervalNanos为帧时间间隔,单位纳秒
       mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
       // CALLBACK_LAST + 1 = 4,创建一个容量为4的CallbackQueue数组,用来存放4种不同的Callback
       mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
       for (int i = 0; i <= CALLBACK_LAST; i++) {
           mCallbackQueues[i] = new CallbackQueue();
       }
    }

    Choreographer类中有一个Looper和一个FrameHandler变量。FrameHandler继承自Handler,了解Android消息机制的自然知道Handler需要Looper来调度消息进行处理。

    FrameHandler是Choreographer的一个内部类,其定义如下:

    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:
                   // 请求VSYNC信号
                   doScheduleVsync();
                   break;
               case MSG_DO_SCHEDULE_CALLBACK:
                   doScheduleCallback(msg.arg1);
                   break;
           }
       }
    }

    FrameHandler的实现非常简单,只处理三类消息,具体的常量标识为:

    private static final int MSG_DO_FRAME = 0;
    private static final int MSG_DO_SCHEDULE_VSYNC = 1;
    private static final int MSG_DO_SCHEDULE_CALLBACK = 2;

    下面代码创建一个容量为4的CallbackQueue数组,用来存放4种不同的Callback。

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

    具体是哪四种CallBack,通过如下代码可知即Input callback、Animation callback、Traversal callback、Commit callback,分别表示输入、动画、布局绘制、提交操作。

    /**
    * 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;
    /**
    * 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 = 3; // 这一类型是在API level=23的时候添加的
  3. 获取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.
        * @throws
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值