我们的起点设置为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;
}
}