本文转载自微信公众号「Android开发编程」,作者Android开发编程。转载本文请联系Android开发编程公众号。
十余年品牌的成都网站建设公司,超过千家企业网站设计经验.价格合理,可准确把握网页设计诉求.提供定制网站建设、购物商城网站建设、微信小程序、响应式网站开发等服务,我们设计的作品屡获殊荣,是您值得信赖的专业网站设计公司。
Android平台提供两种信号,一种是硬件信号,另一种是软件信号,由SurfaceFlinger进程的一个线程定时发出,硬件信号由硬件发出;
App进程若要通过gpu实现图像绘制,需要在接收到Vsync信号的条件下进行,因此,App进程访问SurfaceFlinger进程获取这个信号,再进行gpu绘制;
Android4.1之后增加了Choreographer机制,用于同Vsync机制配合,统一动画、输入和绘制时机;
Choreographer就是负责获取Vsync同步信号并控制App线程(主线程)完成图像绘制的类;
今天我们就来聊聊Choreographer机制;
- public ViewRootImpl(Context context, Display display) {
- ...
- //获取Choreographer实例
- mChoreographer = Choreographer.getInstance();
- ...
- }
- public static Choreographer getInstance() {
- return sThreadInstance.get();
- }
- 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, int vsyncSource) {
- mLooper = looper;
- //使用当前线程looper创建 mHandler
- mHandler = new FrameHandler(looper);
- //USE_VSYNC 4.1以上默认是true,表示 具备接受VSync的能力,这个接受能力就是FrameDisplayEventReceiver
- mDisplayEventReceiver = USE_VSYNC
- ? new FrameDisplayEventReceiver(looper, vsyncSource)
- : null;
- mLastFrameTimeNanos = Long.MIN_VALUE;
- // 计算一帧的时间,Android手机屏幕是60Hz的刷新频率,就是16ms
- mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
- // 创建一个链表类型CallbackQueue的数组,大小为5,
- //也就是数组中有五个链表,每个链表存相同类型的任务:输入、动画、遍历绘制等任务(CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL)
- 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));
- }
- //输入事件,首先执行
- public static final int CALLBACK_INPUT = 0;
- //动画,第二执行
- public static final int CALLBACK_ANIMATION = 1;
- //插入更新的动画,第三执行
- public static final int CALLBACK_INSETS_ANIMATION = 2;
- //绘制,第四执行
- public static final int CALLBACK_TRAVERSAL = 3;
- //提交,最后执行,
- public static final int CALLBACK_COMMIT = 4;
五种类型任务对应存入对应的CallbackQueue中;
每当收到 VSYNC 信号时,Choreographer 将首先处理 INPUT 类型的任务,然后是 ANIMATION 类型,最后才是 TRAVERSAL 类型。
- 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(); // 请求VSYNC信号
- break;
- case MSG_DO_SCHEDULE_CALLBACK:
- doScheduleCallback(msg.arg1);
- break;
- }
- }
- }
- @Override
- public void requestLayout() {
- if (!mHandlingLayoutInLayoutRequest) {
- checkThread();//检查是否在当前线程
- mLayoutRequested = true;//mLayoutRequested 是否measure和layout布局。
- scheduleTraversals();
- }
- }
- void scheduleTraversals() {
- if (!mTraversalScheduled) {//同一帧内不会多次调用遍历
- mTraversalScheduled = true;
- mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();//拦截同步Message
- //Choreographer回调,执行绘制操作
- mChoreographer.postCallback(
- Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
- }
- }
- mChoreographer.postCallback(
- Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
- postCallback()->postCallbackDelayed()->postCallbackDelayedInternal():
- private void postCallbackDelayedInternal(int callbackType,
- Object action, Object token, long delayMillis) {
- synchronized (mLock) {
- // 当前时间
- final long now = SystemClock.uptimeMillis();
- // 回调执行时间,为当前时间加上延迟的时间
- final long dueTime = now + delayMillis;
- // obtainCallbackLocked(long dueTime, Object action, Object token)会将传入的3个参数转换为CallbackRecord(具体请看源码,非主要部分,此处略过),然后CallbackQueue根据回调类型将CallbackRecord添加到链表上。
- mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
- if (dueTime <= now) {
- // 如果delayMillis=0的话,dueTime=now,则会马上执行
- scheduleFrameLocked(now);
- } else {
- // 如果dueTime>now,则发送一个what为MSG_DO_SCHEDULE_CALLBACK类型的定时消息,等时间到了再处理,其最终处理也是执行scheduleFrameLocked(long now)方法
- Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
- msg.arg1 = callbackType;
- msg.setAsynchronous(true);
- mHandler.sendMessageAtTime(msg, dueTime);
- }
- }
- }
- private void scheduleFrameLocked(long now) {
- if (!mFrameScheduled) {
- mFrameScheduled = true;
- if (USE_VSYNC) {
- // 如果使用了VSYNC,由系统值确定
- if (DEBUG_FRAMES) {
- Log.d(TAG, "Scheduling next frame on vsync.");
- }
- if (isRunningOnLooperThreadLocked()) {
- // 请求VSYNC信号,最终会调到Native层,Native处理完成后触发FrameDisplayEventReceiver的onVsync回调,回调中最后也会调用doFrame(long frameTimeNanos, int frame)方法
- scheduleVsyncLocked();
- } else {
- // 在UI线程上直接发送一个what=MSG_DO_SCHEDULE_VSYNC的消息,最终也会调到scheduleVsyncLocked()去请求VSYNC信号
- Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
- msg.setAsynchronous(true);
- mHandler.sendMessageAtFrontOfQueue(msg);
- }
- } else {
- // 没有使用VSYNC
- final long nextFrameTime = Math.max(
- mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
- if (DEBUG_FRAMES) {
- Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
- }
- // 直接发送一个what=MSG_DO_FRAME的消息,消息处理时调用doFrame(long frameTimeNanos, int frame)方法
- Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
- msg.setAsynchronous(true);
- mHandler.sendMessageAtTime(msg, nextFrameTime);
- }
- }
- }
- // Enable/disable vsync for animations and drawing.
- private static final boolean USE_VSYNC = SystemProperties.getBoolean(
- "debug.choreographer.vsync", true);
常量USE_VSYNC,表示是否允许动画和绘制的垂直同步,默认是为true;
判断USE_VSYNC,如果使用了VSYNC:走scheduleVsyncLocked,即请求VSYNC信号,最终调用doFrame;
如果没使用VSYNC,则通过消息执行doFrame;
请求VSYNC信号的流程;
- private void scheduleVsyncLocked() {
- mDisplayEventReceiver.scheduleVsync();
- }
- 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);
- }
- }
- private final class FrameDisplayEventReceiver extends DisplayEventReceiver implements Runnable {
- private boolean mHavePendingVsync;
- private long mTimestampNanos;
- private int mFrame;
- @Override
- public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
- //忽略来自第二显示屏的Vsync
- if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
- scheduleVsync();
- return;
- }
- ...
- mTimestampNanos = timestampNanos;
- mFrame = frame;
- //该消息的callback为当前对象FrameDisplayEventReceiver
- Message msg = Message.obtain(mHandler, this);
- msg.setAsynchronous(true);
- //此处mHandler为FrameHandler
- mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
- }
- @Override
- public void run() {
- mHavePendingVsync = false;
- doFrame(mTimestampNanos, mFrame);
- }
- }
- void doFrame(long frameTimeNanos, int frame) {
- final long startNanos;
- synchronized (mLock) {
- ...
- //是否有跳帧,如果有那么就打印log并且修正偏差
- }
- //执行callback
- try {
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
- AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
- mFrameInfo.markInputHandlingStart();
- doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
- mFrameInfo.markAnimationsStart();
- doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
- mFrameInfo.markPerformTraversalsStart();
- doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
- doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
- } finally {
- AnimationUtils.unlockAnimationClock();
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
- if (DEBUG_FRAMES) {
- final long endNanos = System.nanoTime();
- Log.d(TAG, "Frame " + frame + ": Finished, took "
- + (endNanos - startNanos) * 0.000001f + " ms, latency "
- + (startNanos - frameTimeNanos) * 0.000001f + " ms.");
- }
- }
doFrame方法做的就是渲染下一帧,检测是否卡顿并修补卡顿,然后开始做渲染工作,doCallbacks方法的参数:
- void doCallbacks(int callbackType, long frameTimeNanos) {
- CallbackRecord callbacks;
- synchronized (mLock) {
- final long now = SystemClock.uptimeMillis();
- //从指定类型的CallbackQueue队列中查找执行时间到的CallbackRecord
- callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
- if (callbacks == null) {
- return;
- }
- mCallbacksRunning = true;
- }
- try {
- //由于CallbackQueues是按时间先后顺序排序的,因此遍历执行所有时间到的CallbackRecord
- for (CallbackRecord c = callbacks; c != null; c = c.next) {
- c.run(frameTimeNanos);
- }
- } finally {
- synchronized (mLock) {
- mCallbacksRunning = false;
- do {
- final CallbackRecord next = callbacks.next;
- recycleCallbackLocked(callbacks);
- callbacks = next;
- } while (callbacks != null);
- }
- }
- }
Choreographer内部维护了这四种链表,渲染每一帧的时候都会从上往下的去执行相应的渲染操作,有输入那么就先渲染输入队列,有动画就渲染动画,然后遍历,然后提交;
网站题目:屏幕刷新机制Choreographer原理分析
标题网址:http://www.shufengxianlan.com/qtweb/news26/289926.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联