小言_互联网的博客

Android界面显示_视图Choreographer控制

329人阅读  评论(0)

Android界面显示_视图Choreographer控制

  • GPU/CPU生产帧率和屏幕消费帧率的生产者消费者模式

  • 掉帧,双缓存,三缓存

  • SurfaceFlinger进程发出vsync信号

  • Choreographer(ThreadLocal持有,即ui线程持有)负责获取Vsync同步信号并控制App线程(主线程)完成图像绘制的类

  • 主线程中初始化变量时,创建Choreographer对象,绑定主线程Looper

  • Choreographer通过DisplayEventReceiver通过JNI调用,利用Binder机制接收surfaceflinger进程底层Vsync信号,请求帧画面显示控制。在需要绘制时,发起请求。底层初始化(nativeInit),发起请求(scheduleVsync),实现回调(dispatchVsync)

  • DisplayEventReceiver收到底层各种类型的信号,在doFrame()方法中处理doCallbacks(int callbackType, long frameTimeNanos)

    void doFrame(long frameTimeNanos, int frame) {
      ...
    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);
                doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
    
                mFrameInfo.markPerformTraversalsStart();
                doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
    
                doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
            } finally {
                AnimationUtils.unlockAnimationClock();
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
      ...
    }
    
  • callbackType类型:

    • Choreographer.CALLBACK_INPUT(控制同步处理输入Input)
    • Choreographer.CALLBACK_ANIMATION(控制同步动画Animation)
    • Choreographer.CALLBACK_TRAVERSAL(触发ViewRootImpl的doTraversal方法,实现一次遍历绘制)
    • Choreographer.CALLBACK_INSETS_ANIMATION
    • Choreographer.CALLBACK_COMMIT(遍历完成的提交操作,用来修正动画启动时间)
  • 自定义doFrame监听每一帧渲染时间,获取设备当前帧率(开源项目:Tiny Dancer)

    Choreographer.getInstance().postFrameCallback(new FPSFrameCallback());
    
    public class FPSFrameCallback implements Choreographer.FrameCallback{
    @Override
      public void doFrame(long frameTimeNanos){
          //do something
      }
    
    
  • doCallbacks代码如下:

    void doCallbacks(int callbackType, long frameTimeNanos) {
            CallbackRecord callbacks;
            synchronized (mLock) {
                // We use "now" to determine when callbacks become due because it's possible
                // for earlier processing phases in a frame to post callbacks that should run
                // in a following phase, such as an input event that causes an animation to start.
                final long now = System.nanoTime();
                callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                        now / TimeUtils.NANOS_PER_MS);
                if (callbacks == null) {
                    return;
                }
                mCallbacksRunning = true;
    
                // Update the frame time if necessary when committing the frame.
                // We only update the frame time if we are more than 2 frames late reaching
                // the commit phase.  This ensures that the frame time which is observed by the
                // callbacks will always increase from one frame to the next and never repeat.
                // We never want the next frame's starting frame time to end up being less than
                // or equal to the previous frame's commit frame time.  Keep in mind that the
                // next frame has most likely already been scheduled by now so we play it
                // safe by ensuring the commit time is always at least one frame behind.
                if (callbackType == Choreographer.CALLBACK_COMMIT) {
                    final long jitterNanos = now - frameTimeNanos;
                    Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
                    if (jitterNanos >= 2 * mFrameIntervalNanos) {
                        final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
                                + mFrameIntervalNanos;
                        if (DEBUG_JANK) {
                            Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
                                    + " ms which is more than twice the frame interval of "
                                    + (mFrameIntervalNanos * 0.000001f) + " ms!  "
                                    + "Setting frame time to " + (lastFrameOffset * 0.000001f)
                                    + " ms in the past.");
                            mDebugPrintNextFrameTimeDelta = true;
                        }
                        frameTimeNanos = now - lastFrameOffset;
                        mLastFrameTimeNanos = frameTimeNanos;
                    }
                }
            }
            try {
                Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
                for (CallbackRecord c = callbacks; c != null; c = c.next) {
                    if (DEBUG_FRAMES) {
                        Log.d(TAG, "RunCallback: type=" + callbackType
                                + ", action=" + c.action + ", token=" + c.token
                                + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                    }
                    c.run(frameTimeNanos);
                }
            } finally {
                synchronized (mLock) {
                    mCallbacksRunning = false;
                    do {
                        final CallbackRecord next = callbacks.next;
                        recycleCallbackLocked(callbacks);
                        callbacks = next;
                    } while (callbacks != null);
                }
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }
    

    从mCallbackQueues中取出CallbackRecord,for循环遍历执行c.run(frameTimeNanos);

  • CallbackRecord代码如下:

        private static final class CallbackRecord {
            public CallbackRecord next;
            public long dueTime;
            public Object action; // Runnable or FrameCallback
            public Object token;
    
            @UnsupportedAppUsage
            public void run(long frameTimeNanos) {
                if (token == FRAME_CALLBACK_TOKEN) {
                    ((FrameCallback)action).doFrame(frameTimeNanos);
                } else {
                    ((Runnable)action).run();
                }
            }
        }
    

    CallbackRecord的run方法中((Runnable)action).run();

  • CallbackRecord对象中的(Runnable)action是我们在ViewRootImpl类当中的InvalidateOnAnimationRunnable、mConsumedBatchedInputRunnable、mTraversalRunnable添加到Choreographer中来的。那么回到View的流程中,比如收到Vsync信号后,就会回调mTraversalRunnable的run()方法,再次发起一次measure、layout、draw流程,那么也就和Vsync信号对接上了


转载:https://blog.csdn.net/pangrui201/article/details/106039772
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场