Android Handler源碼之消息發(fā)送

消息發(fā)送

創(chuàng)建消息

創(chuàng)建消息使用下面的代碼:

Message msg = Message.obtain(); // 實(shí)例化消息對(duì)象
msg.what = 1; // 消息標(biāo)識(shí)
msg.obj = "AA"; // 消息內(nèi)容存放
handler.sendMessage(msg);

創(chuàng)建消息,獲取Message對(duì)象,最好的方法是調(diào)用Message.obtain(),而不是直接通過(guò)new Message()的方式,因?yàn)镸essage.obtain()是從一個(gè)可回收的對(duì)象池中獲取Message對(duì)象,避免了重復(fù)創(chuàng)建。

關(guān)于Message的源碼分析可以看下這篇文章:
Messgae源碼分析

發(fā)送消息

查看一下Handler的類結(jié)構(gòu)圖:




Handler發(fā)送消息主要有sendMessage和post兩種方案,

  1. send方案發(fā)送消息
  • sendMessage(Message) 立即發(fā)送Message到消息隊(duì)列
  • sendMessageAtFrontOfQueue(Message) 立即發(fā)送Message到隊(duì)列,而且是放在隊(duì)列的最前面
  • sendMessageAtTime(Message,long) 設(shè)置時(shí)間,發(fā)送Message到隊(duì)列
  • sendMessageDelayed(Message,long) 延時(shí)若干毫秒后,發(fā)送Message到隊(duì)列
  1. post方案
  • post(Runnable) 立即發(fā)送Message到消息隊(duì)列
  • postAtFrontOfQueue(Runnable) 立即發(fā)送Message到隊(duì)列,而且是放在隊(duì)列的最前面
  • postAtTime(Runnable,long) 設(shè)置時(shí)間,發(fā)送Message到隊(duì)列
  • postDelayed(Runnable,long) 在延時(shí)若干毫秒后,發(fā)送Message到隊(duì)列

下面先從send方案中的第一個(gè)sendMessage() 開(kāi)始源碼跟蹤。

send方式

sendMessage()

發(fā)送消息在執(zhí)行了handler.sendMessage(msg)之后,我們往下追蹤源碼。
調(diào)用了下面的方法:

public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}

繼續(xù)調(diào)用了sendMessageDelayed(msg, 0)方法:

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

發(fā)現(xiàn)繼續(xù)調(diào)用了sendMessageAtTime()方法,繼續(xù)往下看:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
 // 1
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    // 2
    return enqueueMessage(queue, msg, uptimeMillis);
}

這個(gè)方法主要做了兩件事,

  • 1、獲取消息隊(duì)列,并對(duì)該消息隊(duì)列做非空判斷,如果為null,直接返回。
  • 2、調(diào)用了enqueueMessage()方法,第一步獲取的消息隊(duì)列也作為了參數(shù)。

enqueueMessage()

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        // 1
    msg.target = this;
    // 2
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    // 3
    return queue.enqueueMessage(msg, uptimeMillis);
}

主要做了三件事:

  • 1、msg.target = this,設(shè)置了msg的target變量,將target指向自己。查看Message.java的源碼,target實(shí)際上是Handler對(duì)象。
  • 2、mAsynchronous是控制著Handler發(fā)送同步異步消息的,在這里先簡(jiǎn)單提一下異步的作用,這里的異步主要是針對(duì)Message中的障柵(Barrier),當(dāng)出現(xiàn)障柵(Barrier)時(shí),同步消息會(huì)被阻塞,而異步消息不會(huì)被阻塞。后面會(huì)有單獨(dú)的文章介紹Handler的同步消息和異步消息。這里mAsynchronous為false,mAsynchronous是控制著Handler發(fā)送異步消息的,在Handler初始化時(shí),在Handler構(gòu)造方法里,傳了false:
public Handler() {
    this(null, false);
}

在下面Handler的構(gòu)造方法里,將mAsynchronous設(shè)置為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;
    mAsynchronous = async;
}

3、調(diào)用MessageQueue的enqueueMessage()方法。

繼續(xù)看enqueueMessage()方法。

boolean enqueueMessage(Message msg, long when) {

        // 1 判斷msg的target變量是否為null,如果為null則拋出異常
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    
    // 2 判斷msg的標(biāo)志位,此時(shí)msg應(yīng)該是要入隊(duì),msg的標(biāo)志位應(yīng)該是還未被使用,如果是已使用狀態(tài),很明顯是有問(wèn)題的,直接拋出異常
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }
    
        // 3 加入同步鎖
    synchronized (this) {
    
    // 4 判斷消息隊(duì)列是否是關(guān)閉狀態(tài),如果是關(guān)閉狀態(tài),return false消息入隊(duì)失敗,并且回收消息
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }
        
                // 5 設(shè)置msg的when,修改msg的標(biāo)志位為已使用狀態(tài)
        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        // 6 主要是用來(lái)判斷要入隊(duì)的msg是否位于隊(duì)列頭部。第一個(gè)msg時(shí),mMessages為null,所以該msg應(yīng)該位于頭部
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            // 把msg的下一個(gè)元素設(shè)置為p,p是mMessages,mMessages此
            //時(shí)為null,所以第一個(gè)message的next指向了null
            msg.next = p;
            // 把msg設(shè)置為鏈表的頭部元素
            mMessages = msg;
            // needWake需要根據(jù)mBlocked的情況考慮是否觸發(fā),如果有阻
            // 塞,則需要喚醒,讓它立刻去拿消息處理
            needWake = mBlocked;
        } else {  // 7 如果上面三個(gè)條件都不滿足則說(shuō)明要把msg插入到中間的位置
        // 8 ,如果頭部元素不是障柵(barrier)或者異步消息,而且還是插入
        // 中間的位置,我們是不喚醒消息隊(duì)列的
        needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            // 9 不斷遍歷消息隊(duì)列,根據(jù)when的比較找到合適的插入
            // Message的位置
            for (;;) {
                    // 設(shè)置前一個(gè)message指針
                prev = p;
                // 設(shè)置下一個(gè)message指針
                p = p.next;
                // 10
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            // 11
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        // 12
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}
  • 第一步,判斷msg的target變量是否為null,如果為null則拋出異常。
  • 第二步,判斷msg的標(biāo)志位,此時(shí)msg應(yīng)該是要入隊(duì),msg的標(biāo)志位應(yīng)該是還未被使用,如果是已使用狀態(tài),很明顯是有問(wèn)題的,直接拋出異常。
  • 第三步,加入同步鎖。
  • 第四步,判斷消息隊(duì)列是否是關(guān)閉狀態(tài),如果是關(guān)閉狀態(tài),return false消息入隊(duì)失敗,并且回收消息。
  • 第五步,設(shè)置msg的when,修改msg的標(biāo)志位為已使用狀態(tài)。
  • 第六步,主要是用來(lái)判斷要入隊(duì)的msg是否位于隊(duì)列頭部。如果p==null則說(shuō)明msg是消息隊(duì)列的第一個(gè)消息;when == 0 表示立即執(zhí)行;when< p.when 表示 msg的執(zhí)行時(shí)間早與鏈表中的頭部元素的時(shí)間,所以上面三個(gè)條件,哪個(gè)條件成立,都要把msg設(shè)置成消息隊(duì)列中鏈表的頭部是元素。
  • 第七步,如果上面三個(gè)條件都不滿足則說(shuō)明要把msg插入到中間的位置。
  • 第八步,如果頭部元素不是障柵(barrier)或者異步消息,而且還是插入中間的位置,我們是不喚醒消息隊(duì)列的。
  • 第九步,進(jìn)入一個(gè)死循環(huán),mMessages是第一個(gè)message,prev = p,將p的值賦值給prev,前面p指mMessage,所以此處prev指向了mMessage,即隊(duì)列中的第一個(gè)message。p = p.next,p指向了隊(duì)列中的第二個(gè)message,以此類推,實(shí)現(xiàn)了消息指針的移動(dòng)。
  • 第十步,跳出循環(huán)條件,p==null,說(shuō)明沒(méi)有下一個(gè)元素,即消息隊(duì)列到末尾了。p!=null&&when < p.when 說(shuō)明當(dāng)前需要入隊(duì)的這個(gè)message的執(zhí)行時(shí)間是小于小于隊(duì)列中p指向的message的執(zhí)行時(shí)間的,也就是說(shuō)這個(gè)需要入隊(duì)的message比p指向的message先執(zhí)行,說(shuō)明這個(gè)位置剛好是這個(gè)入隊(duì)的message的,這樣就跳出循環(huán)。
  • 第十一步,跳出循環(huán)后,主要做了兩件事,第一,將入隊(duì)的這個(gè)msg的next指向循環(huán)中獲取到的應(yīng)該排在這個(gè)消息之后的message。第二,將msg前面的message.next指向了msg。這樣msg就完成了入隊(duì)。
  • 第十二步,如果需要喚醒,則喚醒,調(diào)用native的方法。

整個(gè)流程可以用下面的圖片表示:


第一個(gè)message入隊(duì)

第二個(gè)message入隊(duì)

message入隊(duì)

總結(jié):遍歷消息隊(duì)列中的所有消息,根據(jù)when的比較,找到合適的message的入隊(duì)位置。

sendMessageAtFrontOfQueue()

查看源碼:

public final boolean sendMessageAtFrontOfQueue(Message msg) {
    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, 0);
}

和sendMessageAtTime()大體上一樣,唯一的區(qū)別是該方法在調(diào)用enqueueMessage()方法時(shí),最后一個(gè)參數(shù)是0。
查看MessageQueue的enqueueMessage()方法發(fā)現(xiàn),當(dāng)when==0時(shí),會(huì)一直走if語(yǔ)句的內(nèi)容,msg會(huì)一直插在消息隊(duì)列的頭部。

if (p == null || when == 0 || when < p.when) {
    // New head, wake up the event queue if blocked.
    msg.next = p;
    mMessages = msg;
    needWake = mBlocked;
}else{
    ......省略代碼
}

sendEmptyMessage

sendEmptyMessage()方法,調(diào)用了sendEmptyMessageDelayed()方法

public final boolean sendEmptyMessage(int what)
{
    return sendEmptyMessageDelayed(what, 0);
}

sendEmptyMessageDelayed()方法,內(nèi)阻組裝了一個(gè)僅有what的Message,然后調(diào)用sendMessageDelayed(),從這不開(kāi)始就跟sendMessage()往后的流程相同。

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}

sendEmptyMessageAtTime

查看源碼,直接調(diào)用了sendEmptyMessageAtTime()。

public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageAtTime(msg, uptimeMillis);
}

以上就是發(fā)送消息的send方案,最終都會(huì)走向了enqueueMessage()方法。


post方式

查看post方式的源碼,可以看到,在方法內(nèi)部,還是調(diào)用了sendMessageDelayed()方法,最終也會(huì)走到上面的send流程,最終調(diào)用enqueueMessage()方法。這其中有個(gè)getPostMessage()方法。

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

查看getPostMessage()的源碼

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

這個(gè)方法主要做了兩件事:

  • 通過(guò)Message.obtain()從消息對(duì)象池中獲取一個(gè)空的messgae
  • 將這個(gè)空的message的callback變量指向Runnable

所以我們知道boolean post(Runnable r)方法的內(nèi)置也是通過(guò)Message.obtain()來(lái)獲取一個(gè)Message對(duì)象m,然后僅僅把m的callback指向參數(shù)r而已。最后最終通過(guò)調(diào)用send方案的某個(gè)流程最終調(diào)用到boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)。

總結(jié)

Handler的發(fā)送消息,無(wú)論是通過(guò)send方案還是pos方案最終都會(huì)做走到 boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)中。

?著作權(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ù)。

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