android源码学习-View绘制流程

我们的起点设置为View.setVisibility();

1、View.setVisibility(View.VISIBLE);

2、View.setFlags(visibility, VISIBILITY_MASK);

3、判断flag是否有变化,有变化并且不为GONE状态的话,则请求requestLayout()方法

if ((changed & GONE) != 0) {
            needGlobalAttributesUpdate(false);
            requestLayout();

 

4、requestLayout方法中,请求mParent.requestLayout(),ViewParent.requestLayout()。一级一级的向上请求。

5、最上面一级的ViewParent为ViewRootImpl,则最终会调用到ViewRootImpl类中的requestLayout方法。(为什么View的最上层的ViewParent是ViewRootImpl,可以参见另外一篇文章android源码学习-View如何关联到Window)

可以看到有一个checkThread的方法。之所以不能非主线程绘制,就是因为这里做了线程安全检查。

 @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();//这里检查线程
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

然后会调用scheduleTraversals()方法。

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

这里我们注意到有一个postSyncBarrier方法,插入了一条屏障消息。messageQueue中如果识别到了屏障消息,则会跳过同步消息去执行后面的异步消息。当前执行线程是主线程,所以不用担心会有那种异步消息来不及插入的操作。

 

6、scheduleTraversals方法中调用下面这一句。

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

所以在Choreographer中,postCallback方法通过层层调用,最终会调用到Choreographer的postCallbackDelayedInternal方法

 

7、postCallbackDelayedInternal方法中,首先把任务action对象加入到一个链表当中。mCallbackQueues是一个数组,数组的每个元素是一个链表(PS:有点类似于hashmap的结构)。这里加入的是数组的第1位的链表。

因为delayMillis=0,所以dueTime==now,所以这里走的是调用scheduleFrameLocked方法的逻辑。

这里生成异步message,上面因为插入了屏障消息,所以这里的message会优先被执行。

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

8.sheduleFrameLocked()方法

FrameHanlder中接收到MSG_DO_SCHEDULE_CALLBACK后, 会调用doScheduleCallback方法。

 private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
            mFrameScheduled = true;
            //目前大多数手机都是使用VSYNC信号量的,所以走的是这段逻辑。
            if (USE_VSYNC) {
               //这个判断是是否属于当前线程,上面是主线程通知刷新UI的,所以这里肯定为true
                if (isRunningOnLooperThreadLocked()) {
                    scheduleVsyncLocked();
                } else {
                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtFrontOfQueue(msg);
                }
            } else {
                final long nextFrameTime = Math.max(
                        mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
                if (DEBUG_FRAMES) {
                    Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
                }
                Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, nextFrameTime);
            }
        }
    }

9、scheduleVsyncLocked方法会直接调用DisplayEventReceiver的scheduleVsync方法。然后就直接走native逻辑了。

  private void scheduleVsyncLocked() {
        mDisplayEventReceiver.scheduleVsync();
    }

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

10、这时候也许会看的一脸懵逼,为什么这就结束了呢?但是仔细看一看,DisplayEventReceiver这是一个广播,是广播那自然就有接收广播的地方。所以我们看一下mDisplayEventReceiver的实现类:FrameDisplayEventReceiver。

这里接收的地方就是onVsync方法。其实这个就是android的sync机制,即每16.67ms通知一次。如果错过本地的通知,那么就会跟着下一次通知发出sync广播。

因为mDisplayEventReceiver本身实现了Runnable接口,所以生成Message的时候,直接把自身传入,然后传递给Handler让切换到主线程执行它的run方法。然后在run方法中调用doFrame方法

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

 

11、doFrame方法中,会调用用很多doCallBacks方法。

这分为四个事件,输入,动画,渲染,提交运行。一般动画用于渲染监控使用,比如腾讯GT检测界面渲染用的就是这个原理。

我们暂且只看用户实际渲染的: doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

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

11、遍历队列,执行上面插入队列中的Runnable。其实就是步骤6中的mTraversalRunnable

 void doCallbacks(int callbackType, long frameTimeNanos) {
        CallbackRecord callbacks;
        synchronized (mLock) {
           ...
         callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                    now / TimeUtils.NANOS_PER_MS);
            ...
        try {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
            for (CallbackRecord c = callbacks; c != null; c = c.next) {//遍历队列,执行上面插入队列中的runnable
                if (DEBUG_FRAMES) {
                    Log.d(TAG, "RunCallback: type=" + callbackType
                            + ", action=" + c.action + ", token=" + c.token
                            + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
                }
                c.run(frameTimeNanos);
            }
         ...
    }
CallBackRecord中会去执行最终的mTraversalRunnable。

12、ViewRootImpl.TraversalRunnable中直接调用ViewRootImpl的doTraversal()方法->调用performTraversals()方法,并且移除同步屏障消息。
13、performTraversals是整个绘制流程的核心。一般情况下会调用一次measure、一次layout、一次draw。极限情况下会调用两次measure。
private void performTraversals(){
	...
                     // Ask host how big it wants to be
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);//触发首次measure
	...
                    boolean measureAgain = false;

                    if (lp.horizontalWeight > 0.0f) {
                        width += (int) ((mWidth - width) * lp.horizontalWeight);
                        childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
                                MeasureSpec.EXACTLY);
                        measureAgain = true;
                    }
                    if (lp.verticalWeight > 0.0f) {
                        height += (int) ((mHeight - height) * lp.verticalWeight);
                        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
                                MeasureSpec.EXACTLY);
                        measureAgain = true;
                    }

                    if (measureAgain) {//如果windowManager.LayoutParams的horizontalWeight或verticalWeight大于0,则会再次触发一次measure
                        if (DEBUG_LAYOUT) Log.v(mTag,
                                "And hey let's measure once more: width=" + width
                                + " height=" + height);
                        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                    }

                    layoutRequested = true;
       	...
        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
        boolean triggerGlobalLayoutListener = didLayout
                || mAttachInfo.mRecomputeGlobalAttributes;
        if (didLayout) {//只要ViewRootImpl触发requestLayout,mLayoutRequested=true,则didLayout=true
            performLayout(lp, mWidth, mHeight);//触发layout
	...
        if (!cancelDraw && !newSurface) {
            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).startChangingAnimations();
                }
                mPendingTransitions.clear();
            }

            performDraw();//draw是真正绘制到界面上
        ...

        mIsInTraversal = false;
    }
}

 

 

 

你可能感兴趣的:(安卓源码探究)