最全Handler源碼解剖

Handler使用主要作用一句話概括:線程間通信

在日常開發中主要作用於兩方面:
1、在UI線程進行耗時操作時,將耗時操作拋到子線程進行處理,否則容易ANR。
2、在子線程中刷新UI。

一、Handler簡介

[Handler]、[Looper]、[MessageQueue] 和 [Message] 是組成Handler通信機制的基礎。

1.1Handler簡單使用

Handler的使用基本如以下代碼所示,或者繼承Handler重寫handleMessage,處理不同what標識的Message。不是本文討論的重點,不做過多敘述。

//創建子線程HandlerHandlerThread mHandlerThread = new HandlerThread("daqi");
mHandlerThread.start();
Handler mHandler = new Handler(mHandlerThread.getLooper());//創建MessageMessage message = mHandler.obtainMessage();//發送MessagemHandler.sendMessage(message);//postmHandler.post(new Runnable() {    @Override
    public void run() {

    }
});

1.2Handler工作流程

創建Handler,並綁定Looper -> Handler發送Message -> Message存儲到Looper的MessageQueue中 -> Looper在MessageQueue中拿取頂部Message -> 將Message發送給目標Handler

webp

Handler、Looper、MessageQueue 和 Message的關係:

  • 一個線程只能有一個Looper;

  • 一個Handler只能綁定一個Looper;

  • 多個Handler可以綁定同一個Looper;

  • 一個Looper管理着一個MessageQueue。

  • MssageQueue作爲Message“收信箱”,收納着Handler發送的Message。

二、提出問題

帶着問題看源碼:

1、Looper如何確保線程中只有一個單例。

2、爲什麼建議使用Handler#obtainMessage()獲取Message對象,而不是直接new。

3、Handler的sendMessage() 和 post()有什麼區別。

4、Looper如何管理Message隊列(即先後發送不同延遲時間的Message,Message隊列如何排序)。

5、removeCallbacks、removeMessages 和 removeCallbacksAndMessages都移除了什麼。

推薦閱讀:阿里騰訊Android開發十年,到中年危機就只剩下這套移動架構體系了!

三、源碼分析

3.1、Looper機制

Handler在創建時,默認構造方法會綁定當前線程。所以我們選擇先從Handler的默認構造方法看起。

#Handler.java//無參構造函數public Handler() {   this(null, false);
}public Handler(Callback callback, boolean async) {    //....

    mLooper = Looper.myLooper();    if (mLooper == null) {        throw new RuntimeException(            "Can't create handler inside thread " + Thread.currentThread()
            + " that has not called Looper.prepare()");
    }
     mQueue = mLooper.mQueue;
     mCallback = callback;
}

創建Handler對象時,無參構造函數會獲取當前線程的Looper並獲取到其MessageQueue存儲到Handler自身變量中。

但我們也觀察到,如果沒有Looper的Thread中創建,會拋出RuntimeException,並告訴你該線程無Looper。

webp

從Handler的默認構造方法中得知,在創建Handler前,需要先在當前線程中創建Looper對象和MessageQueue對象。而創建Looper對象和MessageQueue對象只需要調用如下方法:

Looper.prepare();Looper.loop();

prepare的意思是準備,即可以猜測Looper是在Looper#prepare()中初始化的,所以先從Looper#prepare()的源碼看起:

#Looper.java//主要用於作爲存儲的Looper實例的key。static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}public static void prepare() {
    prepare(true);
}private static void prepare(boolean quitAllowed) {    //ThreadLocal#get()獲取當前線程的looper對象
    if (sThreadLocal.get() != null) {        //如果Looper已經實例化完,則會拋出異常
        throw new RuntimeException("Only one Looper may be created per thread");
    }    //如果之前當前線程沒有初始化過Looper,則創建Looper並添加到sThreadLocal中
    sThreadLocal.set(new Looper(quitAllowed));
}

我們發現Looper#prepare()調用重載函數Looper#prepare(boolean)。在這方法中,Looper會被初始化。查看Looper私有構造函數,發現Looper會初始化MessageQueue並存儲當前線程。

而Looper被初始化是有一個前提的,即sThreadLocal.get() == null。否則會拋出RuntimeException,並告訴你該線程只能創建一個Looper對象。

webp

sThreadLocal是Looper類中定義的一個靜態ThreadLocal常量。繼續查看ThreadLocal#get()和ThreadLocal#set()方法。

#ThreadLocal.javapublic T get() {    //獲取當前線程    
    Thread t = Thread.currentThread();    //線程中存在一個ThreadLocal.ThreadLocalMap類型的變量
    //根據當前線程thread獲取到對應的ThreadLocal.ThreadLocalMap變量。
    ThreadLocalMap map = getMap(t);    if (map != null) {        //this表示Looper類中的靜態ThreadLocal常量sThreadLocal
        //因爲sThreadLocal是靜態常量,作爲“key”,確保變量爲單例。
        //根據sThreadLocal獲取到對應的ThreadLocalMap.Entry值。
        ThreadLocalMap.Entry e = mapgetEntry(this);        if (e != null) {            //從ThreadLocalMap.Entry中獲取到對應的Looper,
            @SuppressWarnings("unchecked")
            T result = (T)e.value;            return result;
        }
    }    return setInitialValue();
}public void set(T value) {    //獲取當前線程    
    Thread t = Thread.currentThread();    //線程中存在一個ThreadLocal.ThreadLocalMap類型的變量
    //根據當前線程thread獲取到對應的ThreadLocal.ThreadLocalMap變量。
    ThreadLocalMap map = getMap(t);    if (map != null)        //將sThreadLocal作爲“key”,Looper實例作爲“value”存儲到ThreadLocal.ThreadLocalMap中
        map.set(this, value);    else
        //創建Map並存儲值
        createMap(t, value);
}void createMap(Thread t, T firstValue) {    //創建ThreadLocalMap,構造方法中傳入第一次存儲的鍵值對,並賦值到當前線程的threadLocals變量中。
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

可以觀察到,get()和set()方法獲取當前線程中的ThreadLocal.ThreadLocalMap變量。再將Looper#sThreadLocal作爲key,存儲或獲取對應的value,而value就是當前線程創建的Looper實例。

get()時是根據當前線程獲取的Looper單例,再結合Looper#prepare(boolean),可以知道單個線程只會生成Looper單個實例。

問題1:Looper如何確保線程中只有一個單例。

回答:將Looper構造方法私有化。通過Looper的靜態方法,確保只創建一次Looper對象,再將靜態常量sThreadLocal作爲key,Looper對象作爲value,存儲到當前線程的ThreadLocal.ThreadLocalMap變量中。

查看完Looper初始化的流程,再看看Looper#loop()的源碼

#Looper.javapublic static void loop() {    //獲取當前線程的Looper
    final Looper me = myLooper();    //如果Looper沒有初始化,則拋異常
    if (me == null) {        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }    //從Looper實例中獲取當前線程的MessageQueue
    final MessageQueue queue = me.mQueue;    //消息循環(通過for循環)
    for (;;) {        //1、從消息隊列中獲取消息
        Message msg = queue.next(); 
        if (msg == null) {            //沒有消息表明消息隊列正在退出。
            return;
        }        //省略代碼.....
        //2、將Message發送給其標記的targetHandler
        msg.target.dispatchMessage(msg);        //省略代碼.....

        //3、回收可繼續使用的Message
        msg.recycleUnchecked();
    }
}

Looper#loop()主要做3件事:

1、不斷從MessageQueue中取出Message,若暫無Message,則無限等待
2、將Message發送給目標Handler進行處理
3、回收Message對象

但發現有一種情況,當next獲取到的Message爲空時,則會退出Looper#loop()方法,即意味着消息循環結束。那什麼時候MessageQueue#next()返回null?

#MessageQueue.javaMessage next() {    //如果消息循環已經退出並處理掉,請返回此處。
    //如果應用程序嘗試在退出後重新啓動looper,則可能會發生這種情況。
    //即MessageQueue調用了quit()方法,再次調用Looper#looper()方法時。
    final long ptr = mPtr;    if (ptr == 0) {        return null;
    }    //決定消息隊列中消息出隊的等待時間 or 標記爲無限等待狀態
    int nextPollTimeoutMillis = 0;    for (;;) {        //.....

        // nativePollOnce方法在native層方法。
        //若是nextPollTimeoutMillis爲-1,則無限等待,此時消息隊列處於等待狀態。
        //若是nextPollTimeoutMillis爲0,則無需等待立即返回。
        //若nextPollTimeoutMillis>0,最長阻塞nextPollTimeoutMillis毫秒(超時),如果期間有程序喚醒會立即返回。
        nativePollOnce(ptr, nextPollTimeoutMillis);        //嘗試檢索下一條消息。 如果找到則返回。
        synchronized (this) {            //獲取從開機到現在的毫秒數
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;            //獲取MessageQueue中的頂層Message
            Message msg = mMessages;            //.....
            if (msg != null) {                //如果massage的時間大於當前時間
                //Message的when = Handler發送Message1時的開機時間SystemClock.uptimeMillis() + Message自身的延遲時間
                if (now < msg.when) {                    // 下一條消息尚未就緒。 設置該Message的等待時間以在準備就緒時喚醒。
                    //將msg.when - now(當前開機時間) 得到該Message需要多久之後發送。
                    //則刷新nextPollTimeoutMillis的值,設置等待時間。
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {//否則馬上發送Message

                    //只有當msg.target == null時,prevMsg纔會賦值。
                    //遵從Handler#obtainMessage()則一般不爲空,此情況不考慮。
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {                        //剛開始時prevMsg爲空
                        //則mMessages(頂層Message)指向當前頂層Message的下一個Message
                        mMessages = msg.next;
                    }                    //將返回的Message的下一個Message引用置空。
                    msg.next = null;
                    msg.markInUse();                    return msg;
                }
            } else {                //如果MessageQueue中沒有Message,則會將nextPollTimeoutMillis重置爲-1,繼續等待
                nextPollTimeoutMillis = -1;
            }            //.....
        }        //.....
    }
}

從源碼開頭得知,當MessageQueue退出時,MessageQueue#next()則會返回Message對象爲空,從而關閉消息循環。

MessageQueue#next()主要進行等待操作返回Message操作。而等待操作分兩種情況:

1、MessageQueue隊列中無Message,則進行無限等待操作。

2、當Message還沒到處理時間時,則計算該Message還需要等待的時間,進行相應時間的延遲。

查看Handler如何處理Message:

#Handler.javapublic void dispatchMessage(Message msg) {    if (msg.callback != null) {        //如果Message的callback不爲空,則將消息交由Message的callback處理
        handleCallback(msg);
    } else {        if (mCallback != null) {            //如果Handler的callback不爲空,則將消息交由Handler的callback處理
            if (mCallback.handleMessage(msg)) {                return;
            }
        }        //最後才交由Handler的handleMessage()方法處理。
        handleMessage(msg);
    }
}

Handler#dispatchMessage()主要作用時將Message分發處理。

當該Message對象的callback爲空,目標Handler的callback也爲空時,才輪到handleMessage()進行消息處理。

3.2、Message的循環再用機制

創建Message對象時,我們一般會調用Handler#obtainMessage()獲取Message對象,而不是直接new。先從Handler#obtainMessage()開始查看原由:

#Handler.javapublic final Message obtainMessage(){    return Message.obtain(this);
}
#Message.java//Message鏈表,sPool是表頭private static Message sPool;//記錄當前鏈表中的數量private static int sPoolSize = 0;public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;    return m;
}public static Message obtain() {    //加鎖
    synchronized (sPoolSync) {        if (sPool != null) {
            Message m = sPool;            //鏈表表頭指向其下一個對象,即將表頭從鏈表中取出
            sPool = m.next;            //重置返回的Message的一些信息
            m.next = null;
            m.flags = 0; // clear in-use flag
            //鏈表數量減一
            sPoolSize--;            return m;
        }
    }    //如果鏈表表頭爲空,則new Message對象。
    return new Message();
}

Message#obtain(Handler)調用了重載方法Message#obtain()獲取到Message對象並將Message的目標設置爲調用Handler#obtainMessage()的Message。

Message對象中擁有一個Message類型的next對象,可通過next屬性連成一個Message鏈表。Message中維繫着一個靜態Message鏈表,當鏈表不爲空時,取出表頭的Message進行返回,否則new一個Message對象。

之前查看Looper#loop()源碼時獲知,Looper#loop()最後會調用Message#recycleUnchecked(),將Message進行回收。

#Message.java//Message鏈表最大存儲數量值private static final int MAX_POOL_SIZE = 50;

void recycleUnchecked() {    //將消息保留在循環對象池中時將其標記爲正在使用。
    //清除所有其他細節。
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;    //加鎖
    synchronized (sPoolSync) {        //當前鏈表存儲數量小於最大值,則繼續回收
        if (sPoolSize < MAX_POOL_SIZE) {            //next代表的是該需要回收的Message自身的next對象
            //將自身的next指向原表頭,
            next = sPool;            //自身替換爲表頭,則通過表頭的加減實現該Message鏈表的增加和刪除。
            sPool = this;            //鏈表存儲數量加一
            sPoolSize++;
        }
    }
}

Message#recycleUnchecked()將Message的參數重置,並判斷當前Messag鏈表存儲的數量是否小於最大存儲值,若小於最大存儲值,則將該Message存儲到鏈表中,重複使用。
Message通過對鏈表表頭的增刪操作來進行鏈表的增減。

問題2:爲什麼建議使用Handler#obtainMessage()獲取Message對象,而不是直接new。

回答:Message的回收機制其實是享元設計模式的實現,Message對象存在需要反覆、較大規模創建的情況,使用享元設計模式可以減少創建對象的數量,以減少內存佔用和提高性能。

總結

  • Message對象中擁有一個Message類型的next對象,可通過next屬性連成一個Message鏈表。

  • Message類中維繫着個靜態Message鏈表,並標記其存儲的數量值。

  • 調用Handler#obtainMessage()或Message#obtain()方法時,嘗試從該靜態鏈表中獲取循環再用的Message對象,否則new Message對象返回出去。

  • 當Message被Handler處理完後,Looper對象會調用Message#recycleUnchecked()將Message進行回收,並存儲到靜態Message鏈表中。

3.3、Handler兩條發送路徑:sendMessage 和 post

我們都知道,Handler可以通過sendMessage和post進行消息的發送,這兩種方法到底有什麼區別?先從sendMessage看起:

#Handler.javapublic final boolean sendMessage(Message msg){    //發送一個0延遲的message
    return sendMessageDelayed(msg, 0);
}public final boolean sendMessageDelayed(Message msg, long delayMillis){    //延遲值不能小於0
    if (delayMillis < 0) {
        delayMillis = 0;
    }    //將延遲的時間和開機時間相加
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}public boolean sendMessageAtTime(Message msg, long uptimeMillis) {    //獲取Handler創建時存儲的當前線程的MessageQueue
     MessageQueue queue = mQueue;     if (queue == null) {
         RuntimeException e = new RuntimeException(                 this + " sendMessageAtTime() called with no mQueue");
         Log.w("Looper", e.getMessage(), e);         return false;
    }    return enqueueMessage(queue, msg, uptimeMillis);
}private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {    //將Message的目標TargetHandler設置爲當前Handler
    //如果通過Handler#obtainMessage()獲取的Message早設置了TargetHandler爲當前Handler,一般是新new的Message才爲空。
    msg.target = this;    if (mAsynchronous) {
         msg.setAsynchronous(true);
    }    return queue.enqueueMessage(msg, uptimeMillis);
}

一路都是方法的嵌套,其中最關鍵的就是在傳遞給sendMessageAtTime()方法前,將延時時間和手機開機時間相加,得到Message對象的"執行時間"。

在繼續查看MessageQueue#enqueueMessage():

#MessageQueue.java//標記MessageQueue#next()的nativePollOnce()是否以 非零超時等待(無限等待)被阻止。private boolean mBlocked;

boolean enqueueMessage(Message msg, long when) {    //.....

    synchronized (this) {        //...

        msg.markInUse();        //將延遲時間和開機時間相加得到的時間值存儲到message的when變量中。
        msg.when = when;        //獲取鏈表表頭的Message
        Message p = mMessages;
        boolean needWake;        //當表頭爲空時,或者本次發送的Message對象“執行時間”比表頭的時間要小時
        if (p == null || when == 0 || when < p.when) {            //將本次發送的Message存儲到表頭前面,將next屬性指向原鏈表表頭
            msg.next = p;            //刷新MessageQueue中指向表頭的變量
            mMessages = msg;
            needWake = mBlocked;
        } else {            //通常不需要喚醒事件隊列,除非隊列的頭部有屏障,並且消息是隊列中最早的異步消息。
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;            //開啓循環,便利MessageQueue的Message鏈表
            for (;;) {                //prev先指向原表頭,後續循環中,不斷指向下一個元素
                prev = p;                //p指向下一個元素
                p = p.next;                //如果p== null,表示到鏈表的尾部
                //或者本次發送的Message對象的“執行時間”when比下一個元素的“執行時間”要短
                if (p == null || when < p.when) {                    //推出循環
                    break;
                }                //...
            }            //此時,prev指向的Message對象的when 比本次發送的Message對象msg的when小,即“執行時間”比它小。
            //p可能爲空,即鏈表尾;或者p指向的Message對象的when比 比本次發送的Message對象msg的when大,即“執行時間”比它大。
            // 即可能存在 prev.when < msg.when <p.when 或 prev.when < msg.when
            //將msg的next變量指向p所指的對象
            msg.next = p;            //prev所指向的message對象的next變量指向msg
            prev.next = msg;
        }        //判斷是否需要喚醒之前在MessageQueue#next()中“陷入沉睡”的nativePollOnce()方法。
        if (needWake) {
            nativeWake(mPtr);
        }
    }    return true;
}

MessageQueue#enqueueMessage()主要作用是:

1、依據msg.when的大小,按從小到大的順序,將msg插入到MessageQueue的Message鏈表中。

2、對於馬上執行的message,直接喚醒,停止nativePollOnce()的無限等待,讓MessageQueue#next返回繼續執行,從Message鏈表中取出Message,交由Looper對象進行處理。

模擬情況:
同時發送延遲400毫秒的Message對象 和 延遲300毫秒的Message對象;
100毫秒後,再發送延遲延遲250毫秒的Message對象;

情景分析:

同時發送兩個分別延遲400和延遲300的Message對象,此時系統開機時間 time = SystemClock.uptimeMillis();

延遲400的Message對象:msg400, msg400 .when = time + 400;。
首先進入MessageQueue的Message鏈表,由於原本Message鏈表爲空,p == null,表頭mMessages指 msg400

延遲300的Message對象:msg300, msg300.when = time + 300;。
進入if(p == null || when == 0 || when < p.when)語句 ,p != null ,msg300.when < msg400.when , msg300.next 指向 msg400,鏈表表頭指向msg300;

100毫秒後,發送延遲延遲250毫秒的Message對象。此時系統開機時間 time2 = SystemClock.uptimeMillis(),相對time 大了100毫秒,即time2 = time + 100毫秒。

延遲250的Message對象:msg250, msg250.when = time2 + 250, 即msg250.when = time + 350。
進入if(p == null || when == 0 || when < p.when)語句,語句不成立,進入遍歷Message鏈表的for循環。when < p.when判斷中,msg250.when > msg300.when,循環繼續。msg250.when < msg400.when,跳出循環。執行msg.next = p; 和 prev.next = msg;兩個語句,即msg250.next = msg400,msg300.next = msg250。

問題4:Looper如何管理Message隊列(即先後發送不同延遲時間的Message,Message隊列如何排序)。

回答:Message通過SystemClock.uptimeMillis() + 延遲時間給自身when賦值,通過值的大小作爲執行順序。SystemClock.uptimeMillis() 不根據當前時區的時間變化而變化,只會因開關機而被重置,否則始終自增。
所以可以根據當前的SystemClock.uptimeMillis() 與Message對象的when對比,知道馬上執行還是延遲多少秒後才執行。

轉換到Handler#ost()的源碼:

#Handler.javapublic final boolean post(Runnable r){    return  sendMessageDelayed(getPostMessage(r), 0);
}private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;    return m;
}public void dispatchMessage(Message msg) {    if (msg.callback != null) {        //如果Message的callback不爲空,則將消息交由Message的callback處理
        handleCallback(msg);
    } else {        if (mCallback != null) {            //如果Handler的callback不爲空,則將消息交由Handler的callback處理
            if (mCallback.handleMessage(msg)) {                return;
            }
        }        //最後才交由Handler的handleMessage()方法處理。
        handleMessage(msg);
    }
}private static void handleCallback(Message message) {    //只是調用callback的run()方法。
    message.callback.run();
}

post()傳遞的Runnable對象會被套上一層Message外殼,最後走和sendMessage()一樣的路線。

Runnable對象將存儲在Message對象的callback對象中。在Handler處理Message時,由於callback對象不爲空,調用Handler#handleCallback()對Runnable對象調用run()方法,實現Message的處理。

問題3:Handler的sendMessage() 和 post()有什麼區別。

回答:post()會將Runnable對象轉換爲Message對象,並把Runnable對象存儲在Message對象的callback中,然後繼續走sendMessage()的路線。
在Handler處理Message對象時,post()方法產生的Message對象中callback不爲空,由Handler調用Runnable對象的run方法,不會調用handleMessage();

3.4、Message的移除

#Handler.javapublic final void removeMessages(int what) {
    mQueue.removeMessages(this, what, null);
}public final void removeCallbacks(Runnable r){
    mQueue.removeMessages(this, r, null);
}public final void removeMessages(int what, Object object) {
    mQueue.removeMessages(this, what, object);
}public final void removeCallbacks(Runnable r, Object token){
    mQueue.removeMessages(this, r, token);
}
#MessageQueue.javavoid removeMessages(Handler h, int what, Object object) {    //...
    synchronized (this) {        //獲取Message鏈表表頭
        Message p = mMessages;        //從頭開始尋找,尋找第一個不符合條件的Message。分兩種情況:
        //1、鏈表表頭直接不符合移除條件,即第一個不符合條件的Message爲鏈表表頭,推出循環。
        //2、鏈表符合移除條件,將鏈表表頭指向原表頭的下一個Message,並回收原鏈表表頭。新的鏈表表頭繼續進行判斷,直到出現不符合移除條件的Message出現。
        //最後鏈表表頭mMessages 和 p都指向第一個不符合條件的Message,前面符合移除條件的Message已被移除。
        while (p != null && p.target == h && p.what == what
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }        //從第一個不符合條件的Message對象開始,迭代尋找其下一個Message是否符合移除條件。
        while (p != null) {
            Message n = p.next;            if (n != null) {                //判斷是否符合移除條件
                if (n.target == h && n.what == what
                    && (object == null || n.obj == object)) {                    //獲取p.next().next()的Message對象,即下下個對象。
                    Message nn = n.next;                    //符合條件的回收
                    n.recycleUnchecked();                    //將原本的下下個Message轉移到next對象中,即轉移到下一個Message的位置上。
                    p.next = nn;                    continue;
                }
            }            //n == null,表示到鏈尾了,則 p == null,while循環結束。
            p = n;
        }
    }
}

void removeMessages(Handler h, Runnable r, Object object) {    if (h == null || r == null) {        return;
    }
    synchronized (this) {
        Message p = mMessages;        // Remove all messages at front.
        while (p != null && p.target == h && p.callback == r
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }        // Remove all messages after front.
        while (p != null) {
            Message n = p.next;            if (n != null) {                if (n.target == h && n.callback == r
                    && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;                    continue;
                }
            }
            p = n;
        }
    }
}
    removeMessages(Handler, **int**, Object) 根據Message中的**what**進行刷選移除對象。
    removeMessages(Handler, **Runnable**,Object)則根據相同的**Runnable**對象進行刷選移除。

    兩者的都是走相同的移除對象流程,只是其中的一種刷選條件有所不同,what針對的是Handler#sendMessage()發送的Message,Runnable針對的是Handler#post()發送的Message。

    Handler#removeCallbacksAndMessages()則移除這兩種刷選條件,針對所有Message。

問題5:removeCallbacks、removeMessages 和 removeCallbacksAndMessages都移除了什麼

回答:removeCallbacks、removeMessages 和 removeCallbacksAndMessages 在待處理的Message鏈表中,根據各自的刷選條件尋找符合移除條件的對象,將符合條件的Message移除出Message鏈表,並回收該Message。

四、總結

  • Message對象中擁有一個Message類型的next對象,可通過next屬性連成一個Message鏈表。

  • Message類中維繫着個靜態Message鏈表,存儲着回收的Message對象,等待重複使用。

  • MessageQueue類中也維繫着個靜態Message鏈表,存儲着待處理的Message的對象,等待MessageQueue#next()方法將其取出,交由目標Handler處理。

  • 當用戶調用Handler#obtainMessage()時,嘗試從該Message鏈表中獲取待循環再用的Message,獲取失敗則new一個新的Message對象。
    當Message被目標Handler處理完成後,會被回收到Message類的靜態Message鏈表中。
    當調用Handler一系列remove方法後,被移除的Message會被回收到Message類的靜態Message鏈表中。

  • post方法發送的Runnable對象將會被包裝成一個Message走sendMessage路線,Runnable對象被存儲在Message的callback變量中。

  • 當該Message對象的callback爲空,目標Handler的callback也爲空時,纔將Message交由handleMessage()進行處理。即post方法產生的Message對象會被交由Handler#handleCallback()直接調用run方法,不走Handler#handleMessage()。

  • msg.when = 延時時間 + 手機開機時間。再依據msg.when的大小,按從小到大的順序,將msg插入到MessageQueue的Message鏈表中。

  • Looper類中的靜態ThreadLocal常量作爲key,當前線程的Looper對象做爲value,存儲在當前線程的ThreadLocal.ThreadLocalMap變量。ThreadLocal常量確保key唯一,也就確保value唯一,並且Looper#prepare()只允許創建一遍Looper對象。


    webp

    handler

關於Android進階的全部學習內容,我們這邊都有系統的知識體系以及進階視頻資料,有需要的朋友可以加羣免費領取安卓進階視頻教程,源碼,面試資料,羣內有大牛一起交流討論技術;818520403(包括自定義控件、NDK、架構設計、混合式開發工程師(React native,Weex)、性能優化、完整商業項目開發等)

webp

Android高級進階視頻教程


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章