關(guān)于view.post(r)和handler.post(r)的區(qū)別?

參考:
https://blog.csdn.net/Kitty_Landon/article/details/79235418
https://blog.csdn.net/scnuxisan225/article/details/49815269
其實這兩個的主要區(qū)別是看目前界面有沒有顯示出來或者說在調(diào)用這兩個方法時,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(其實目前它就是為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í)行,那么什么時候執(zhí)行呢?

存放在HandlerAction數(shù)組中的runnable什么時候執(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;
       }
   }

在這個方法里面會調(diào)用handler來post之前存放的Runnable,看下這個方法是什么時候執(zhí)行的?


image.png

dispatchAttachedToWindow是什么時候執(zhí)行的呢?


image.png

我們知道ViewRootImpl的performTraversals會執(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()方法,這個方法內(nèi)部會遍歷HandlerAction數(shù)組,利用Handler來post之前存放的Runnable。

問題來了,dispatchAttachedToWindow方法是在performMeasure方法之前調(diào)用的,既然在調(diào)用的時候還沒有執(zhí)行performMeasure來進行測量,那么為什么在執(zhí)行完dispatchAttachedToWindow方法后就可以獲取到寬高呢?

因為Android系統(tǒng)的運行完全是基于消息驅(qū)動的。
在調(diào)用完dispatchAttachedToWindow方法之后,會將之前調(diào)用view.post(runnable)中的runnable取出來執(zhí)行,這里的執(zhí)行其實是發(fā)送Message到MessageQueue,等待Looper來調(diào)用執(zhí)行,但是也得系統(tǒng)處理完上一個Message

而ViewRootImpl的performTraversals所處的環(huán)境正是一個Runnable對象,這個Runnable也是包裝成Message交給Handler來處理的,所以View.post(runnable)中的runnable執(zhí)行是要在performTraversals方法之后的,并非一調(diào)用dispatchAttachedToWindow就會執(zhí)行。

這個流程分析完了,我們回到View的post方法中

attachInfo什么時候被賦值的呢?

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;
    }
image.png

ViewRootImpl是什么時候被初始化的呢?
在Activity的onResume()方法之后。


image.png

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容