Handler源碼學(xué)習(xí)

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

在日常開(kāi)發(fā)中主要作用于兩方面:</br>
????????1、在UI線程進(jìn)行耗時(shí)操作時(shí),將耗時(shí)操作拋到子線程進(jìn)行處理,否則容易ANR。</br>
????????2、在子線程中刷新UI。</br>

一、Handler簡(jiǎn)介

????????Handler、Looper、MessageQueueMessage 是組成Handler通信機(jī)制的基礎(chǔ)。</br>

1.1Handler簡(jiǎn)單使用

????????Handler的使用基本如以下代碼所示,或者繼承Handler重寫(xiě)handleMessage,處理不同what標(biāo)識(shí)的Message。不是本文討論的重點(diǎn),不做過(guò)多敘述。

//創(chuàng)建子線程Handler
HandlerThread mHandlerThread = new HandlerThread("daqi");
Handler mHandler = new Handler(mHandlerThread.getLooper());
//創(chuàng)建Message
Message message = mHandler.obtainMessage();
//發(fā)送Message
mHandler.sendMessage(message);
//post
mHandler.post(new Runnable() {
    @Override
    public void run() {

    }
});

1.2Handler工作流程

????????創(chuàng)建Handler,并綁定Looper -> Handler發(fā)送Message -> Message存儲(chǔ)到Looper的MessageQueue中 -> Looper在MessageQueue中拿取頂部Message -> 將Message發(fā)送給目標(biāo)Handler

image

Handler、Looper、MessageQueue 和 Message的關(guān)系:</br>

  • 一個(gè)線程只能有一個(gè)Looper;</br>
  • 一個(gè)Handler只能綁定一個(gè)Looper;</br>
  • 多個(gè)Handler可以綁定同一個(gè)Looper;</br>
  • 一個(gè)Looper管理著一個(gè)MessageQueue。</br>
  • MssageQueue作為Message“收信箱”,收納著Handler發(fā)送的Message。</br>

二、提出問(wèn)題

帶著問(wèn)題看源碼:</br>
????1、Looper如何確保線程中只有一個(gè)單例。</br>

????2、為什么建議使用Handler#obtainMessage()獲取Message對(duì)象,而不是直接new。</br>

????3、Handler的sendMessage() 和 post()有什么區(qū)別。</br>

????4、Looper如何管理Message隊(duì)列(即先后發(fā)送不同延遲時(shí)間的Message,Message隊(duì)列如何排序)。</br>

????5、removeCallbacks、removeMessages 和 removeCallbacksAndMessages都移除了什么。</br>

三、源碼分析

3.1、Looper機(jī)制

Handler在創(chuàng)建時(shí),默認(rèn)構(gòu)造方法會(huì)綁定當(dāng)前線程。所以我們選擇先從Handler的默認(rèn)構(gòu)造方法看起。

#Handler.java
//無(wú)參構(gòu)造函數(shù)
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;
}

????????創(chuàng)建Handler對(duì)象時(shí),無(wú)參構(gòu)造函數(shù)會(huì)獲取當(dāng)前線程的Looper并獲取到其MessageQueue存儲(chǔ)到Handler自身變量中。

????????但我們也觀察到,如果沒(méi)有Looper的Thread中創(chuàng)建,會(huì)拋出RuntimeException,并告訴你該線程無(wú)Looper。

image

????????從Handler的默認(rèn)構(gòu)造方法中得知,在創(chuàng)建Handler前,需要先在當(dāng)前線程中創(chuàng)建Looper對(duì)象和MessageQueue對(duì)象。而創(chuàng)建Looper對(duì)象和MessageQueue對(duì)象只需要調(diào)用如下方法:

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

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

#Looper.java
//主要用于作為存儲(chǔ)的Looper實(shí)例的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()獲取當(dāng)前線程的looper對(duì)象
    if (sThreadLocal.get() != null) {
        //如果Looper已經(jīng)實(shí)例化完,則會(huì)拋出異常
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //如果之前當(dāng)前線程沒(méi)有初始化過(guò)Looper,則創(chuàng)建Looper并添加到sThreadLocal中
    sThreadLocal.set(new Looper(quitAllowed));
}

????????我們發(fā)現(xiàn)Looper#prepare()調(diào)用重載函數(shù)Looper#prepare(boolean)。在這方法中,Looper會(huì)被初始化。查看Looper私有構(gòu)造函數(shù),發(fā)現(xiàn)Looper會(huì)初始化MessageQueue并存儲(chǔ)當(dāng)前線程。

????????而Looper被初始化是有一個(gè)前提的,即sThreadLocal.get() == null。否則會(huì)拋出RuntimeException,并告訴你該線程只能創(chuàng)建一個(gè)Looper對(duì)象。


image

????????sThreadLocal是Looper類中定義的一個(gè)靜態(tài)ThreadLocal常量。繼續(xù)查看ThreadLocal#get()和ThreadLocal#set()方法。

#ThreadLocal.java

public T get() {
    //獲取當(dāng)前線程    
    Thread t = Thread.currentThread();
    //線程中存在一個(gè)ThreadLocal.ThreadLocalMap類型的變量
    //根據(jù)當(dāng)前線程thread獲取到對(duì)應(yīng)的ThreadLocal.ThreadLocalMap變量。
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        //this表示Looper類中的靜態(tài)ThreadLocal常量sThreadLocal
        //因?yàn)閟ThreadLocal是靜態(tài)常量,作為“key”,確保變量為單例。
        //根據(jù)sThreadLocal獲取到對(duì)應(yīng)的ThreadLocalMap.Entry值。
        ThreadLocalMap.Entry e = mapgetEntry(this);
        if (e != null) {
            //從ThreadLocalMap.Entry中獲取到對(duì)應(yīng)的Looper,
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

public void set(T value) {
    //獲取當(dāng)前線程    
    Thread t = Thread.currentThread();
    //線程中存在一個(gè)ThreadLocal.ThreadLocalMap類型的變量
    //根據(jù)當(dāng)前線程thread獲取到對(duì)應(yīng)的ThreadLocal.ThreadLocalMap變量。
    ThreadLocalMap map = getMap(t);
    if (map != null)
        //將sThreadLocal作為“key”,Looper實(shí)例作為“value”存儲(chǔ)到ThreadLocal.ThreadLocalMap中
        map.set(this, value);
    else
        //創(chuàng)建Map并存儲(chǔ)值
        createMap(t, value);
}

void createMap(Thread t, T firstValue) {
    //創(chuàng)建ThreadLocalMap,構(gòu)造方法中傳入第一次存儲(chǔ)的鍵值對(duì),并賦值到當(dāng)前線程的threadLocals變量中。
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

????????可以觀察到,get()和set()方法獲取當(dāng)前線程中的ThreadLocal.ThreadLocalMap變量。再將Looper#sThreadLocal作為key,存儲(chǔ)或獲取對(duì)應(yīng)的value,而value就是當(dāng)前線程創(chuàng)建的Looper實(shí)例。

????????get()時(shí)是根據(jù)當(dāng)前線程獲取的Looper單例,再結(jié)合Looper#prepare(boolean),可以知道單個(gè)線程只會(huì)生成Looper單個(gè)實(shí)例。

問(wèn)題1:Looper如何確保線程中只有一個(gè)單例。

????????回答:將Looper構(gòu)造方法私有化。通過(guò)Looper的靜態(tài)方法,確保只創(chuàng)建一次Looper對(duì)象,再將靜態(tài)常量sThreadLocal作為key,Looper對(duì)象作為value,存儲(chǔ)到當(dāng)前線程的ThreadLocal.ThreadLocalMap變量中。

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

#Looper.java

public static void loop() {
    //獲取當(dāng)前線程的Looper
    final Looper me = myLooper();
    //如果Looper沒(méi)有初始化,則拋異常
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //從Looper實(shí)例中獲取當(dāng)前線程的MessageQueue
    final MessageQueue queue = me.mQueue;
    
    //消息循環(huán)(通過(guò)for循環(huán))
    for (;;) {
        //1、從消息隊(duì)列中獲取消息
        Message msg = queue.next(); 
        if (msg == null) {
            //沒(méi)有消息表明消息隊(duì)列正在退出。
            return;
        }
        
        //省略代碼.....
        //2、將Message發(fā)送給其標(biāo)記的targetHandler
        msg.target.dispatchMessage(msg);
           
        //省略代碼.....
        
        //3、回收可繼續(xù)使用的Message
        msg.recycleUnchecked();
    }
}

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

????1、不斷從MessageQueue中取出Message,若暫無(wú)Message,則無(wú)限等待。</br>
????2、將Message發(fā)送給目標(biāo)Handler進(jìn)行處理。</br>
????3、回收Message對(duì)象。</br>

????????但發(fā)現(xiàn)有一種情況,當(dāng)next獲取到的Message為空時(shí),則會(huì)退出Looper#loop()方法,即意味著消息循環(huán)結(jié)束。那什么時(shí)候MessageQueue#next()返回null?

#MessageQueue.java
Message next() {
    //如果消息循環(huán)已經(jīng)退出并處理掉,請(qǐng)返回此處。
    //如果應(yīng)用程序嘗試在退出后重新啟動(dòng)looper,則可能會(huì)發(fā)生這種情況。
    //即MessageQueue調(diào)用了quit()方法,再次調(diào)用Looper#looper()方法時(shí)。
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    //決定消息隊(duì)列中消息出隊(duì)的等待時(shí)間 or 標(biāo)記為無(wú)限等待狀態(tài)
    int nextPollTimeoutMillis = 0;
    for (;;) {
        //.....
        
        // nativePollOnce方法在native層方法。
        //若是nextPollTimeoutMillis為-1,則無(wú)限等待,此時(shí)消息隊(duì)列處于等待狀態(tài)。
        //若是nextPollTimeoutMillis為0,則無(wú)需等待立即返回。
        //若nextPollTimeoutMillis>0,最長(zhǎng)阻塞nextPollTimeoutMillis毫秒(超時(shí)),如果期間有程序喚醒會(huì)立即返回。
        nativePollOnce(ptr, nextPollTimeoutMillis);
        
        //嘗試檢索下一條消息。 如果找到則返回。
        synchronized (this) {
            //獲取從開(kāi)機(jī)到現(xiàn)在的毫秒數(shù)
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            //獲取MessageQueue中的頂層Message
            Message msg = mMessages;
            
            //.....
            if (msg != null) {
                //如果massage的時(shí)間大于當(dāng)前時(shí)間
                //Message的when = Handler發(fā)送Message1時(shí)的開(kāi)機(jī)時(shí)間SystemClock.uptimeMillis() + Message自身的延遲時(shí)間
                if (now < msg.when) {
                    // 下一條消息尚未就緒。 設(shè)置該Message的等待時(shí)間以在準(zhǔn)備就緒時(shí)喚醒。
                    //將msg.when - now(當(dāng)前開(kāi)機(jī)時(shí)間) 得到該Message需要多久之后發(fā)送。
                    //則刷新nextPollTimeoutMillis的值,設(shè)置等待時(shí)間。
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {//否則馬上發(fā)送Message
                
                    //只有當(dāng)msg.target == null時(shí),prevMsg才會(huì)賦值。
                    //遵從Handler#obtainMessage()則一般不為空,此情況不考慮。
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        //剛開(kāi)始時(shí)prevMsg為空
                        //則mMessages(頂層Message)指向當(dāng)前頂層Message的下一個(gè)Message
                        mMessages = msg.next;
                    }
                    //將返回的Message的下一個(gè)Message引用置空。
                    msg.next = null;
                    msg.markInUse();
                    return msg;
                }
            } else {
                //如果MessageQueue中沒(méi)有Message,則會(huì)將nextPollTimeoutMillis重置為-1,繼續(xù)等待
                nextPollTimeoutMillis = -1;
            }

            //.....
        }

        //.....
    }
}

????????從源碼開(kāi)頭得知,當(dāng)MessageQueue退出時(shí),MessageQueue#next()則會(huì)返回Message對(duì)象為空,從而關(guān)閉消息循環(huán)。

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

????????1、MessageQueue隊(duì)列中無(wú)Message,則進(jìn)行無(wú)限等待操作。

????????2、當(dāng)Message還沒(méi)到處理時(shí)間時(shí),則計(jì)算該Message還需要等待的時(shí)間,進(jìn)行相應(yīng)時(shí)間的延遲。

查看Handler如何處理Message:

#Handler.java
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);
    }
}

????????Handler#dispatchMessage()主要作用時(shí)將Message分發(fā)處理。

????????當(dāng)該Message對(duì)象的callback為空,目標(biāo)Handler的callback也為空時(shí),才輪到handleMessage()進(jìn)行消息處理。

3.2、Message的循環(huán)再用機(jī)制

創(chuàng)建Message對(duì)象時(shí),我們一般會(huì)調(diào)用Handler#obtainMessage()獲取Message對(duì)象,而不是直接new。先從Handler#obtainMessage()開(kāi)始查看原由:

#Handler.java
public final Message obtainMessage(){
    return Message.obtain(this);
}
#Message.java
//Message鏈表,sPool是表頭
private static Message sPool;
//記錄當(dāng)前鏈表中的數(shù)量
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;
            //鏈表表頭指向其下一個(gè)對(duì)象,即將表頭從鏈表中取出
            sPool = m.next;
            //重置返回的Message的一些信息
            m.next = null;
            m.flags = 0; // clear in-use flag
            //鏈表數(shù)量減一
            sPoolSize--;
            return m;
        }
    }
    //如果鏈表表頭為空,則new Message對(duì)象。
    return new Message();
}

????????Message#obtain(Handler)調(diào)用了重載方法Message#obtain()獲取到Message對(duì)象并將Message的目標(biāo)設(shè)置為調(diào)用Handler#obtainMessage()的Message。

????????Message對(duì)象中擁有一個(gè)Message類型的next對(duì)象,可通過(guò)next屬性連成一個(gè)Message鏈表。Message中維系著一個(gè)靜態(tài)Message鏈表,當(dāng)鏈表不為空時(shí),取出表頭的Message進(jìn)行返回,否則new一個(gè)Message對(duì)象。

之前查看Looper#loop()源碼時(shí)獲知,Looper#loop()最后會(huì)調(diào)用Message#recycleUnchecked(),將Message進(jìn)行回收。

#Message.java
//Message鏈表最大存儲(chǔ)數(shù)量值
private static final int MAX_POOL_SIZE = 50;

void recycleUnchecked() {
    //將消息保留在循環(huán)對(duì)象池中時(shí)將其標(biāo)記為正在使用。
    //清除所有其他細(xì)節(jié)。
    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) {
        //當(dāng)前鏈表存儲(chǔ)數(shù)量小于最大值,則繼續(xù)回收
        if (sPoolSize < MAX_POOL_SIZE) {
            //next代表的是該需要回收的Message自身的next對(duì)象
            //將自身的next指向原表頭,
            next = sPool;
            //自身替換為表頭,則通過(guò)表頭的加減實(shí)現(xiàn)該Message鏈表的增加和刪除。
            sPool = this;
            //鏈表存儲(chǔ)數(shù)量加一
            sPoolSize++;
        }
    }
}

????????Message#recycleUnchecked()將Message的參數(shù)重置,并判斷當(dāng)前Messag鏈表存儲(chǔ)的數(shù)量是否小于最大存儲(chǔ)值,若小于最大存儲(chǔ)值,則將該Message存儲(chǔ)到鏈表中,重復(fù)使用。</br>
????????Message通過(guò)對(duì)鏈表表頭的增刪操作來(lái)進(jìn)行鏈表的增減。

問(wèn)題2:為什么建議使用Handler#obtainMessage()獲取Message對(duì)象,而不是直接new。

????????回答:Message的回收機(jī)制其實(shí)是享元設(shè)計(jì)模式的實(shí)現(xiàn),Message對(duì)象存在需要反復(fù)、較大規(guī)模創(chuàng)建的情況,使用享元設(shè)計(jì)模式可以減少創(chuàng)建對(duì)象的數(shù)量,以減少內(nèi)存占用和提高性能。

總結(jié)

  • Message對(duì)象中擁有一個(gè)Message類型的next對(duì)象,可通過(guò)next屬性連成一個(gè)Message鏈表。

  • Message類中維系著個(gè)靜態(tài)Message鏈表,并標(biāo)記其存儲(chǔ)的數(shù)量值。

  • 調(diào)用Handler#obtainMessage()或Message#obtain()方法時(shí),嘗試從該靜態(tài)鏈表中獲取循環(huán)再用的Message對(duì)象,否則new Message對(duì)象返回出去。

  • 當(dāng)Message被Handler處理完后,Looper對(duì)象會(huì)調(diào)用Message#recycleUnchecked()將Message進(jìn)行回收,并存儲(chǔ)到靜態(tài)Message鏈表中。

3.3、Handler兩條發(fā)送路徑:sendMessage 和 post

我們都知道,Handler可以通過(guò)sendMessage和post進(jìn)行消息的發(fā)送,這兩種方法到底有什么區(qū)別?先從sendMessage看起:

#Handler.java

public final boolean sendMessage(Message msg){
    //發(fā)送一個(gè)0延遲的message
    return sendMessageDelayed(msg, 0);
}

public final boolean sendMessageDelayed(Message msg, long delayMillis){
    //延遲值不能小于0
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    //將延遲的時(shí)間和開(kāi)機(jī)時(shí)間相加
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    //獲取Handler創(chuàng)建時(shí)存儲(chǔ)的當(dāng)前線程的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的目標(biāo)TargetHandler設(shè)置為當(dāng)前Handler
    //如果通過(guò)Handler#obtainMessage()獲取的Message早設(shè)置了TargetHandler為當(dāng)前Handler,一般是新new的Message才為空。
    msg.target = this;
    if (mAsynchronous) {
         msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

????????一路都是方法的嵌套,其中最關(guān)鍵的就是在傳遞給sendMessageAtTime()方法前,將延時(shí)時(shí)間和手機(jī)開(kāi)機(jī)時(shí)間相加,得到Message對(duì)象的"執(zhí)行時(shí)間"。

在繼續(xù)查看MessageQueue#enqueueMessage():

#MessageQueue.java

//標(biāo)記MessageQueue#next()的nativePollOnce()是否以 非零超時(shí)等待(無(wú)限等待)被阻止。
private boolean mBlocked;

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

    synchronized (this) {
        //...
        
        msg.markInUse();
        //將延遲時(shí)間和開(kāi)機(jī)時(shí)間相加得到的時(shí)間值存儲(chǔ)到message的when變量中。
        msg.when = when;
        //獲取鏈表表頭的Message
        Message p = mMessages;
        boolean needWake;
        //當(dāng)表頭為空時(shí),或者本次發(fā)送的Message對(duì)象“執(zhí)行時(shí)間”比表頭的時(shí)間要小時(shí)
        if (p == null || when == 0 || when < p.when) {
            //將本次發(fā)送的Message存儲(chǔ)到表頭前面,將next屬性指向原鏈表表頭
            msg.next = p;
            //刷新MessageQueue中指向表頭的變量
            mMessages = msg;
            needWake = mBlocked;
        } else {
            //通常不需要喚醒事件隊(duì)列,除非隊(duì)列的頭部有屏障,并且消息是隊(duì)列中最早的異步消息。
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            //開(kāi)啟循環(huán),便利MessageQueue的Message鏈表
            for (;;) {
                //prev先指向原表頭,后續(xù)循環(huán)中,不斷指向下一個(gè)元素
                prev = p;
                //p指向下一個(gè)元素
                p = p.next;
                //如果p== null,表示到鏈表的尾部
                //或者本次發(fā)送的Message對(duì)象的“執(zhí)行時(shí)間”when比下一個(gè)元素的“執(zhí)行時(shí)間”要短
                if (p == null || when < p.when) {
                    //推出循環(huán)
                    break;
                }
                //...
            }
            //此時(shí),prev指向的Message對(duì)象的when 比本次發(fā)送的Message對(duì)象msg的when小,即“執(zhí)行時(shí)間”比它小。
            //p可能為空,即鏈表尾;或者p指向的Message對(duì)象的when比 比本次發(fā)送的Message對(duì)象msg的when大,即“執(zhí)行時(shí)間”比它大。
            // 即可能存在 prev.when < msg.when <p.when 或 prev.when < msg.when
            //將msg的next變量指向p所指的對(duì)象
            msg.next = p;
            //prev所指向的message對(duì)象的next變量指向msg
            prev.next = msg;
        }

        //判斷是否需要喚醒之前在MessageQueue#next()中“陷入沉睡”的nativePollOnce()方法。
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

MessageQueue#enqueueMessage()主要作用是:</br>

????????1、依據(jù)msg.when的大小,按從小到大的順序,將msg插入到MessageQueue的Message鏈表中。</br>

????????2、對(duì)于馬上執(zhí)行的message,直接喚醒,停止nativePollOnce()的無(wú)限等待,讓MessageQueue#next返回繼續(xù)執(zhí)行,從Message鏈表中取出Message,交由Looper對(duì)象進(jìn)行處理。</br>

模擬情況:</br>
????同時(shí)發(fā)送延遲400毫秒的Message對(duì)象 和 延遲300毫秒的Message對(duì)象;</br>
????100毫秒后,再發(fā)送延遲延遲250毫秒的Message對(duì)象;

情景分析:</br>

????????同時(shí)發(fā)送兩個(gè)分別延遲400和延遲300的Message對(duì)象,此時(shí)系統(tǒng)開(kāi)機(jī)時(shí)間 time = SystemClock.uptimeMillis();

????延遲400的Message對(duì)象:msg400, msg400 .when = time + 400;。</br>
首先進(jìn)入MessageQueue的Message鏈表,由于原本Message鏈表為空,p == null,表頭mMessages指 msg400

????延遲300的Message對(duì)象:msg300, msg300.when = time + 300;。</br>
進(jìn)入if(p == null || when == 0 || when < p.when)語(yǔ)句 ,p != null ,msg300.when < msg400.when , msg300.next 指向 msg400,鏈表表頭指向msg300;

????100毫秒后,發(fā)送延遲延遲250毫秒的Message對(duì)象。此時(shí)系統(tǒng)開(kāi)機(jī)時(shí)間 time2 = SystemClock.uptimeMillis(),相對(duì)time 大了100毫秒,即time2 = time + 100毫秒。

????延遲250的Message對(duì)象:msg250, msg250.when = time2 + 250, 即msg250.when = time + 350。</br>
????進(jìn)入if(p == null || when == 0 || when < p.when)語(yǔ)句,語(yǔ)句不成立,進(jìn)入遍歷Message鏈表的for循環(huán)。when < p.when判斷中,msg250.when > msg300.when,循環(huán)繼續(xù)。msg250.when < msg400.when,跳出循環(huán)。執(zhí)行msg.next = p; 和 prev.next = msg;兩個(gè)語(yǔ)句,即msg250.next = msg400,msg300.next = msg250。

image.png

問(wèn)題4:Looper如何管理Message隊(duì)列(即先后發(fā)送不同延遲時(shí)間的Message,Message隊(duì)列如何排序)。

????????回答:Message通過(guò)SystemClock.uptimeMillis() + 延遲時(shí)間給自身when賦值,通過(guò)值的大小作為執(zhí)行順序。SystemClock.uptimeMillis() 不根據(jù)當(dāng)前時(shí)區(qū)的時(shí)間變化而變化,只會(huì)因開(kāi)關(guān)機(jī)而被重置,否則始終自增。</br>
????????所以可以根據(jù)當(dāng)前的SystemClock.uptimeMillis() 與Message對(duì)象的when對(duì)比,知道馬上執(zhí)行還是延遲多少秒后才執(zhí)行。

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

#Handler.java
public 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) {
    //只是調(diào)用callback的run()方法。
    message.callback.run();
}

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

????????Runnable對(duì)象將存儲(chǔ)在Message對(duì)象的callback對(duì)象中。在Handler處理Message時(shí),由于callback對(duì)象不為空,調(diào)用Handler#handleCallback()對(duì)Runnable對(duì)象調(diào)用run()方法,實(shí)現(xiàn)Message的處理。

問(wèn)題3:Handler的sendMessage() 和 post()有什么區(qū)別。

????????回答:post()會(huì)將Runnable對(duì)象轉(zhuǎn)換為Message對(duì)象,并把Runnable對(duì)象存儲(chǔ)在Message對(duì)象的callback中,然后繼續(xù)走sendMessage()的路線。</br>
????????在Handler處理Message對(duì)象時(shí),post()方法產(chǎn)生的Message對(duì)象中callback不為空,由Handler調(diào)用Runnable對(duì)象的run方法,不會(huì)調(diào)用handleMessage();

3.4、Message的移除

#Handler.java
public 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.java
void removeMessages(Handler h, int what, Object object) {
    //...
    synchronized (this) {
        //獲取Message鏈表表頭
        Message p = mMessages;

        //從頭開(kāi)始尋找,尋找第一個(gè)不符合條件的Message。分兩種情況:
        //1、鏈表表頭直接不符合移除條件,即第一個(gè)不符合條件的Message為鏈表表頭,推出循環(huán)。
        //2、鏈表符合移除條件,將鏈表表頭指向原表頭的下一個(gè)Message,并回收原鏈表表頭。新的鏈表表頭繼續(xù)進(jìn)行判斷,直到出現(xiàn)不符合移除條件的Message出現(xiàn)。
        //最后鏈表表頭mMessages 和 p都指向第一個(gè)不符合條件的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;
        }

        //從第一個(gè)不符合條件的Message對(duì)象開(kāi)始,迭代尋找其下一個(gè)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對(duì)象,即下下個(gè)對(duì)象。
                    Message nn = n.next;
                    //符合條件的回收
                    n.recycleUnchecked();
                    //將原本的下下個(gè)Message轉(zhuǎn)移到next對(duì)象中,即轉(zhuǎn)移到下一個(gè)Message的位置上。
                    p.next = nn;
                    continue;
                }
            }
            //n == null,表示到鏈尾了,則 p == null,while循環(huán)結(jié)束。
            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) 根據(jù)Message中的what進(jìn)行刷選移除對(duì)象。</br>
????????removeMessages(Handler, Runnable,Object)則根據(jù)相同的Runnable對(duì)象進(jìn)行刷選移除。

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

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

問(wèn)題5:removeCallbacks、removeMessages 和 removeCallbacksAndMessages都移除了什么

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

四、總結(jié)

  • Message對(duì)象中擁有一個(gè)Message類型的next對(duì)象,可通過(guò)next屬性連成一個(gè)Message鏈表。
  • Message類中維系著個(gè)靜態(tài)Message鏈表,存儲(chǔ)著回收的Message對(duì)象,等待重復(fù)使用。
  • MessageQueue類中也維系著個(gè)靜態(tài)Message鏈表,存儲(chǔ)著待處理的Message的對(duì)象,等待MessageQueue#next()方法將其取出,交由目標(biāo)Handler處理。
  • 當(dāng)用戶調(diào)用Handler#obtainMessage()時(shí),嘗試從該Message鏈表中獲取待循環(huán)再用的Message,獲取失敗則new一個(gè)新的Message對(duì)象。</br>
    當(dāng)Message被目標(biāo)Handler處理完成后,會(huì)被回收到Message類的靜態(tài)Message鏈表中。</br>
    當(dāng)調(diào)用Handler一系列remove方法后,被移除的Message會(huì)被回收到Message類的靜態(tài)Message鏈表中。
  • post方法發(fā)送的Runnable對(duì)象將會(huì)被包裝成一個(gè)Message走sendMessage路線,Runnable對(duì)象被存儲(chǔ)在Message的callback變量中。
  • 當(dāng)該Message對(duì)象的callback為空,目標(biāo)Handler的callback也為空時(shí),才將Message交由handleMessage()進(jìn)行處理。即post方法產(chǎn)生的Message對(duì)象會(huì)被交由Handler#handleCallback()直接調(diào)用run方法,不走Handler#handleMessage()。
  • msg.when = 延時(shí)時(shí)間 + 手機(jī)開(kāi)機(jī)時(shí)間。再依據(jù)msg.when的大小,按從小到大的順序,將msg插入到MessageQueue的Message鏈表中。
  • Looper類中的靜態(tài)ThreadLocal常量作為key,當(dāng)前線程的Looper對(duì)象做為value,存儲(chǔ)在當(dāng)前線程的ThreadLocal.ThreadLocalMap變量。ThreadLocal常量確保key唯一,也就確保value唯一,并且Looper#prepare()只允許創(chuàng)建一遍L(zhǎng)ooper對(duì)象。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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