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