參考:
https://blog.csdn.net/Kitty_Landon/article/details/79235418
https://blog.csdn.net/scnuxisan225/article/details/49815269
其實(shí)這兩個(gè)的主要區(qū)別是看目前界面有沒有顯示出來或者說在調(diào)用這兩個(gè)方法時(shí)乙嘀,view的dispatchAttachedToWindow方法有沒有執(zhí)行,如果已經(jīng)執(zhí)行過了咐刨,那么他們是沒啥區(qū)別的雕拼,都是利用Handler來發(fā)送Message到MessageQueue,如果dispatchAttachedToWindow還沒有執(zhí)行煞檩,那么他們是有區(qū)別的处嫌,最直觀的判斷就是我們可以在onCreate方法中利用view.post(runnable)來獲取view的寬高,但是無法利用handler.post(runnable)來獲取斟湃。
為什么在onCreate方法中可以利用view.post(runnable)獲取view的寬高熏迹?
看下源代碼:
View#post()
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}
我們假設(shè)目前attachInfo為null(其實(shí)目前它就是為null的,哪兒賦值的凝赛,后面分析)
/**
* Returns the queue of runnable for this view.
*
* @return the queue of runnables for this view
*/
private HandlerActionQueue getRunQueue() {
if (mRunQueue == null) {
mRunQueue = new HandlerActionQueue();
}
return mRunQueue;
}
HandlerActionQueue#post()
public void postDelayed(Runnable action, long delayMillis) {
final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
synchronized (this) {
if (mActions == null) {
mActions = new HandlerAction[4];
}
mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
mCount++;
}
}
可以看到注暗,在調(diào)用了view的post方法之后只是將runnable存放到了HandlerAction的數(shù)組中,并沒有去執(zhí)行墓猎,那么什么時(shí)候執(zhí)行呢捆昏?
存放在HandlerAction數(shù)組中的runnable什么時(shí)候執(zhí)行?
HandlerActionQueue#executeActions()
public void executeActions(Handler handler) {
synchronized (this) {
final HandlerAction[] actions = mActions;
for (int i = 0, count = mCount; i < count; i++) {
final HandlerAction handlerAction = actions[i];
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
mActions = null;
mCount = 0;
}
}
在這個(gè)方法里面會(huì)調(diào)用handler來post之前存放的Runnable毙沾,看下這個(gè)方法是什么時(shí)候執(zhí)行的骗卜?
dispatchAttachedToWindow是什么時(shí)候執(zhí)行的呢?
我們知道ViewRootImpl的performTraversals會(huì)執(zhí)行view的measure搀军、layout膨俐、draw,大致是這樣:
host.dispatchAttachedToWindow()
...
performMeasure();
...
performLayout();
...
performDraw();
理一下:系統(tǒng)調(diào)用ViewRootImpl#performTraversals()方法罩句,performTraversals()方法調(diào)用host的dispatchAttachedToWindow()方法焚刺,host就是DecorView也就是View,接著在View的dispatchAttachedToWindow()方法中調(diào)用mRunQueue.executeActions()方法门烂,這個(gè)方法內(nèi)部會(huì)遍歷HandlerAction數(shù)組乳愉,利用Handler來post之前存放的Runnable。
問題來了屯远,dispatchAttachedToWindow方法是在performMeasure方法之前調(diào)用的蔓姚,既然在調(diào)用的時(shí)候還沒有執(zhí)行performMeasure來進(jìn)行測量,那么為什么在執(zhí)行完dispatchAttachedToWindow方法后就可以獲取到寬高呢慨丐?
因?yàn)锳ndroid系統(tǒng)的運(yùn)行完全是基于消息驅(qū)動(dòng)的坡脐。
在調(diào)用完dispatchAttachedToWindow方法之后,會(huì)將之前調(diào)用view.post(runnable)中的runnable取出來執(zhí)行房揭,這里的執(zhí)行其實(shí)是發(fā)送Message到MessageQueue备闲,等待Looper來調(diào)用執(zhí)行晌端,但是也得系統(tǒng)處理完上一個(gè)Message
而ViewRootImpl的performTraversals所處的環(huán)境正是一個(gè)Runnable對象,這個(gè)Runnable也是包裝成Message交給Handler來處理的恬砂,所以View.post(runnable)中的runnable執(zhí)行是要在performTraversals方法之后的咧纠,并非一調(diào)用dispatchAttachedToWindow就會(huì)執(zhí)行。
這個(gè)流程分析完了泻骤,我們回到View的post方法中
attachInfo什么時(shí)候被賦值的呢漆羔?
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}
ViewRootImpl是什么時(shí)候被初始化的呢?
在Activity的onResume()方法之后狱掂。