Choreographer

2020-04-30  本文已影响0人  杨殿生

他是控制应用进程绘制时机的,会在收到Vsync信号后调用应用进程的刷新

Choreographer创建,他是跟ViewRootImpl一起创建的(在ViewRootImpl的构造函数中)

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

他是通过ThreadLocal存储的也就是说一个线程只有一个Choreographer

DecorView在添加到ViewManager时会调用requestLayout

public void requestLayout() {
   scheduleTraversals();
}
void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        }
    }

1、设置一个标记防止多次调用requestLayout
2、设置消息屏障(屏蔽普通消息,放行异步消息)
3、向Choreographer添加消息

  private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
           ····
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
           ····
            scheduleFrameLocked(now);
    }
private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
                // 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.
                if (isRunningOnLooperThreadLocked()) {
                    scheduleVsyncLocked();
                } else {
                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtFrontOfQueue(msg);
                }
            }
        }
    }

如果当前线程是Choreographer工作线程,通过 scheduleVsyncLocked();向SurfaceFlinger发送Vsync请求(通过socketpair)requestNextVsync,在构造函数中通过parcel获取。BitTube,这个Socket是surfaceflinger创建后传递过来的。否则发送消息到工作线程中

private final class FrameDisplayEventReceiver extends DisplayEventReceiver
            implements Runnable {
    
        @Override
        public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
            ···
            mTimestampNanos = timestampNanos;
            mFrame = frame;
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
        }

        @Override
        public void run() {
            doFrame(mTimestampNanos, mFrame);
        }
    }

信号发送回来会在这里接收到

void doFrame(long frameTimeNanos, int frame) {
       
            long intendedFrameTimeNanos = frameTimeNanos;
            startNanos = System.nanoTime();
            final long jitterNanos = startNanos - frameTimeNanos;
            if (jitterNanos >= mFrameIntervalNanos) {
                final long skippedFrames = jitterNanos / mFrameIntervalNanos;
                //跳过帧数过多
                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;
                frameTimeNanos = startNanos - lastFrameOffset;
            }

            if (frameTimeNanos < mLastFrameTimeNanos) {
                scheduleVsyncLocked();
                return;
            }

            mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
            mFrameScheduled = false;
            mLastFrameTimeNanos = frameTimeNanos;

            ····
            doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
            doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);

    }

执行callback

  void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            performTraversals();
        }
    }

在接到Vsync信号后,执行doTraversal
1、撤销标记位
2、撤销消息屏障
3、执行performTraversals()

请求重绘
上一篇 下一篇

猜你喜欢

热点阅读