Android UI刷新Framwork层流程

2019-10-28  本文已影响0人  tigerzhao

看过电影都知道,连续的场景其实是一帧一帧的静态图像,手机显示也是这样,只不过大部分手机刷新率增加到了每秒60帧,手机显示图像是逐行刷新的,如果一页的图像没有刷新完成,这个时候又有新的图像开始刷新就会产生画面撕裂,android在4.1版本的时候引入了一个黄油计划,用来解决系统UI响应的问题,通过强制垂直同步VSYNC信号来使图像产生和显示达到步调一致。
VSYNC信号是由底层驱动发出来的,上层应用接受这个信号的地方就是Choreographer类中的内部类FrameDisplayEventReceiver。
可以自己写一个自定义View,然后在onDraw方法中设置断点,查看方法调用栈就会发现这其实是一个带有callback的消息,以下是方法调用栈的截图:


1.png

这个callback如下图:


2.png
也可以在模拟器中直接打断点到SDK的代码,更方便。
然后在Handler源码中处理带有callback消息的代码是这样的:
 /**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

handleCallback方法的实现如下:

    private static void handleCallback(Message message) {
        message.callback.run();
    }

而FrameDisplayEventReceiver类继承了Runnable接口,看下具体的实现

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);
        }

        @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() {
            mHavePendingVsync = false;
            doFrame(mTimestampNanos, mFrame);
        }
    }

也就是直接调用了run()方法中的doFrame()方法。看下doFrame()方法的实现

   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);

            mFrameInfo.markPerformTraversalsStart();
            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

            doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
        } finally {
            AnimationUtils.unlockAnimationClock();
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
      ...
    }

执行了doCallbacks()方法,UI刷新执行的是CALLBACK_TRAVERSAL类型的,下面贴上doCallbacks()方法代码

void doCallbacks(int callbackType, long frameTimeNanos) {
        CallbackRecord callbacks;
        synchronized (mLock) {
            final long now = System.nanoTime();
            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                    now / TimeUtils.NANOS_PER_MS);
            if (callbacks == null) {
                return;
            }
            mCallbacksRunning = true;
           ...
        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);
        }
    }

执行callbacks的run方法,而callbacks来自CallbackQueue数组,CallbackQueue本身是一个内部维护了CallbackRecord的链表,继续看这个链表的添加方法

private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        ...
        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }

最终调用这个方法,讲callback传进来的方法是

    public void postCallback(int callbackType, Runnable action, Object token) {
        postCallbackDelayed(callbackType, action, token, 0);
    }

调用Choreographer类这个方法的地方是在ViewRootImpl类里面:

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

mTraversalRunnable就是刷新的callback

final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

doTraversal()的方法

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

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

这里面performTraversals()方法就是开启view界面布局的核心代码,里面执行了performMeasure(),performLayout()等view布局流程的代码。
接着回到最前面,这个带有callback的消息是怎么产生的,这部分内容牵扯到了内核层的代码,而这块我不熟悉,因此参考了git袁的博客。
先来看类Choreographer的内部类FrameDisplayEventReceiver的继承关系:

    private final class FrameDisplayEventReceiver extends DisplayEventReceiver
            implements Runnable

继承了DisplayEventReceiver类,来看下DisplayEventReceiver类的构造函数

    /**
     * Creates a display event receiver.
     *
     * @param looper The looper to use when invoking callbacks.
     * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values.
     * @param configChanged Whether to dispatch config changed events. Must be one of the
     * CONFIG_CHANGED_EVENT_* values.
     */
    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");
    }

在构造函数中调用了JNI方法nativeInit,将Java层的消息队列传进去了,此处属于内核部分的原理,能力有限就不做深究,内核层中产生的vysnc信号,最终会调用到Java层的DisplayEventReceiver类的dispatchVsync方法:

    // Called from native code.
    @SuppressWarnings("unused")
    @UnsupportedAppUsage
    private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
        onVsync(timestampNanos, physicalDisplayId, frame);
    }

而onVsync方法在子类FrameDisplayEventReceiver中的实现就是创建了一个带有callback的msg:

        @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);
        }

mHandler的初始化在Choreographer的构造方法中:

    private Choreographer(Looper looper, int vsyncSource) {
        mLooper = looper;
        mHandler = new FrameHandler(looper);
        mDisplayEventReceiver = USE_VSYNC
                ? new FrameDisplayEventReceiver(looper, vsyncSource)
                : null;
        mLastFrameTimeNanos = Long.MIN_VALUE;

        mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());

        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));
    }

这个looper就是主线程的looper,后续会来一章Choreographer创建的流程追踪。至此刷新UI的入口流程就完成了。

上一篇下一篇

猜你喜欢

热点阅读