Android Choreographer机制

一 概述

在分析 Choreographer 机制之前,同学们需要先了解一些关于 Android 显示系统的一些基础概念和背景。可以参考 Android图形显示系统1 概述

我们知道 Google 在 Android 4.1 系统中对 Android Display 系统进行了优化:在收到 VSync 信号后,将马上开始下一帧的渲染。即一旦收到 VSync 通知,CPU 和 GPU 就立刻开始计算,然后把数据写入 buffer。本篇文章重点分析 Choreographer,以及 Choreographer 与 Vsync 信号之间的交互。

  • Choreographer,意为舞蹈编导、编舞者。在这里就是指对 CPU/GPU 绘制的指导 —— 收到 VSync 信号才开始绘制,保证绘制拥有完整的 16.6ms,避免绘制的随机性
  • Choreographer,是一个 Java 类,包路径 android.view.Choreographer。类注释是 “协调动画、输入和绘图的计时”
  • 通常应用层不会直接使用 Choreographer,而是使用更高级的 API,例如动画和 View 绘制相关的 ValueAnimator.start()、View.invalidate() 等。
  • 业界一般通过 Choreographer 来监控应用的帧率

二 Choreographer启动流程

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

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

2.1 getInstance

Choreographer.java

public static Choreographer getInstance() {
   
        return sThreadInstance.get();
}

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!");
            }
            Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
            if (looper == Looper.getMainLooper()) {
   
                mMainInstance = choreographer;
            }
            return choreographer;
        }
};

可知在 Choreographer 中使用到了 ThreadLocal。当前所在线程为 UI 线程,也就是常说的主线程。

2.2 创建Choreographer

private Choreographer(Looper looper, int vsyncSource) {
   
    mLooper = looper;
    //创建Handler对象,这个handler用于向主线程发送消息
    mHandler = new FrameHandler(looper);
    //创建用于接收VSync信号的对象
    mDisplayEventReceiver = USE_VSYNC ?
            new FrameDisplayEventReceiver(looper, vsyncSource) : null;
    mLastFrameTimeNanos = Long.MIN_VALUE;
    mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
    //创建回调对象,其中CALLBACK_LAST=4
    mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
    for (int i = 0; i <= CALLBACK_LAST; i++) {
   
        mCallbackQueues[i] = new CallbackQueue();
    }
    // b/68769804: For low FPS experiments.
    setFPSDivisor(SystemProperties.getInt(ThreadedRenderer.DEBUG_FPS_DIVISOR, 1));
}
  • mLastFrameTimeNanos:指上一次帧绘制时间点
  • mFrameIntervalNanos:帧间时长,一般等于16.7ms

2.3 创建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,即绘制过程
                    doFrame(System.nanoTime(), 0);
                    break;
                case MSG_DO_SCHEDULE_VSYNC:
                //申请VSYNC信号,例如当前需要绘制任务时
                    doScheduleVsync();
                    break;
                case MSG_DO_SCHEDULE_CALLBACK:
                //需要延迟的任务,最终还是执行上述两个事件
                    doScheduleCallback(msg.arg1);
                    break;
            }
        }
    }

2.4 创建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, CONFIG_CHANGED_EVENT_SUPPRESS);
        }

//关键点:收到 Vsync 信号后的回调
        @Override
        public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
   
            // 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;
            }

            mTimestampNanos = timestampNanos;
            mFrame = frame;
            //将本身作为 runnable 传入 msg, 发消息后会走 run(),即 doFrame(),也是异步消息
            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);
        }
}

2.4.1 DisplayEventReceiver

DisplayEventReceiver.java

public DisplayEventReceiver(Looper looper) {
   
        this(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_SUPPRESS);
}

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

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

        mCloseGuard.open("dispose&#
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值