深入了解Android View 绘制流程

View的绘制还有什么好聊的

前面我们已经减少了view的绘制流程了,很多同学都知道,面试的时候面试官问你:view的绘制流程是什么?绝大部分同学都会脱口而出:onMeasure()->onLayout()-onDraw(),然后把一切的流程给介绍出来,就像我上一篇文章所写的Android View 绘制流程。但是按照现在的android就业形势,如果只会这些“表面”的东西难免会让人缺少眼前一亮的感觉。那么今天我们就深入的了解一下完整的View绘制

谁调用了performTraversals()?

我们知道onMeasure、onLayout、onDraw这几个方法对应的就是ViewRootImp.java里面的performMeasure、performLayout、performDraw方法。这几个方法的入口就是performTraversals()。那么谁调用了performTraversals()方法呢?我们一步一步往下跟。

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

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

            performTraversals();

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

performTraversals()方法由doTraversal方法调用

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

doTraversal()方法是由TraversalRunnable方法调用。那么我们只需要看到谁调用了mTraversalRunnable即可

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

好了,调用链很明确了,就是scheduleTraversal方法触发了View的绘制流程。这个方法有很多的调用地方,最经典的就是View的invalidate()方法了。

View的invalidate流程分析

 void invalidate() {
        mDirty.set(0, 0, mWidth, mHeight);
        if (!mWillDrawSoon) {
            scheduleTraversals();
        }
    }

重中之重scheduleTraversals()

我们看一下scheduleTraversal方法的调用

  mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

这个方法非常的重要。Choreographer的作用就是协调input时间、动画和绘制的时间。其实如果大家知道vsync的话,那么我们就可以说,choreography就是监听vsync的心跳时间的callback,vsync会每隔16.7ms回调一次。我们看choreography源码

private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        if (DEBUG_FRAMES) {
            Log.d(TAG, "PostCallback: type=" + callbackType
                    + ", action=" + action + ", token=" + token
                    + ", delayMillis=" + 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);
            }
        }
    }

我们可以看到发送了一个MSG_DO_SCHEDULE_CALLBACK的消息,再继续往下跟

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();
                    break;
                case MSG_DO_SCHEDULE_CALLBACK:
                    doScheduleCallback(msg.arg1);
                    break;
            }
        }
    }

这里终于可以看到所有的消息的处理了,也包括前面提到的vsync流程

/**
     * Schedules a single vertical sync pulse to be delivered when the next
     * display frame begins.
     */
    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);
        }
    }

这里就是调用native方法去触发vsync了。我们重点看下doFrame()方法

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

这里也就符合我们开头所说的:Choreography方法是协调input、动画、和绘制流程的管理者。这里我们可以做一个引申,为什么android系统可以有动画,每一个动画的执行粒度和区间值是怎么保存和触发的,其实都是跟这个vsync相关联。

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

这里就回调会ViewRootImp.java里面的TraversalRunnable方法中

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

这里就开始和前面的分析流程形成了闭环。
自此上层的View绘制流程就分析完毕了。关于Vsync我们会在接下来的文章继续做分析,待更~~

你可能感兴趣的:(深入了解Android View 绘制流程)