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方法

【android源码学习-View绘制流程】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; } }




    推荐阅读