Handler如何通過sendMessage(Message msg)方法將新消息加入當前消息隊列(二)

這裏假設我們是通過Handler 的 sendMessage(Message msg) 來發送消息的

首先進入 sendMessage 方法

    public final boolean sendMessage(Message msg)
        {
           return sendMessageDelayed(msg, 0);//注意第二個參數傳入的是整數 0
        }


   /**
     * Enqueue a message into the message queue after all pending messages
     * before (current time + delayMillis). You will receive it in
     * {@link #handleMessage}, in the thread attached to this handler.
     *
     * @return Returns true if the message was successfully placed in to the
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }


我們來看一下 sendMessageDelayed 這個方法,通過該方法的註釋我們也可以瞭解到它的作用。這個方法會向消息隊列中插入一條新的消息,也就是消息入隊,重點來關注一下消息入隊的時間。

看下面的註釋:

after all pending messages * before (current time + delayMillis).

大概翻譯過來就是 在所有即將處理的消息之後,在  current time + delayMillis 這個時間點之前 讓消息入隊。

delayMilis 就是我們需要讓這個消息延遲多久之後發送,如果我們通過sendMessage(Message msg)這個方法來發送消息的話,默認延遲的時間是 0,也就是delayMillis=0,顯然這個 current time 就是  SystemClock.uptimeMillis()  返回的時間。

進入SystemClock 查看該方法:

/**
     * Returns milliseconds since boot, not counting time spent in deep sleep.
     *
     * @return milliseconds of non-sleep uptime since boot.
     */
    @CriticalNative
    native public static long uptimeMillis();

uptimeMillis()方法返回的就是 從開機開始到現在的時間總數,以ms爲單位,其中不包括系統深度睡眠的時間

網上介紹這個方法的文章也很多,可以自己百度一下。下面是Google官方文檔,感興趣的可以瞭解下

https://developer.android.google.cn/reference/android/os/SystemClock.html?hl=en

我們接着往下走,其實不論通過哪種方法發送消息最終都會走到下面的這個方法裏面

    /**
     * Enqueue a message into the message queue after all pending messages
     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
     * Time spent in deep sleep will add an additional delay to execution.
     * You will receive it in {@link #handleMessage}, in the thread attached
     * to this handler.
     *
     * @param uptimeMillis The absolute time at which the message should be
     *         delivered, using the
     *         {@link android.os.SystemClock#uptimeMillis} time-base.
     *
     * @return Returns true if the message was successfully placed in to the
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;//就是文章(一)中介紹的Handler對應的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);
    }

注意註釋中對於參數 uptimeMillis 的描述,它確定了發送該消息的精確時間。

接下來進入 enqueueMessage ,該方法最終進入了MessageQueue的同名方法中

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//指定了該消息的target爲本Handler
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);//調用MessageQueue的方法
    }

我們詳細看一下MessageQueue 的 enqueueMessage方法 ,該方法裏包含了消息入隊的核心代碼

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

        synchronized (this) {
            ......
            
            msg.markInUse();//標記該消息正在使用中
            //when 就是上面傳入的 SystemClock.uptimeMillis() + delayMillis
            msg.when = when;//when代表了該消息發送的精確時間 
            Message p = mMessages;//將p指向消息隊列的頭部
            boolean needWake;
            //以下代碼分別代表了三種不同的情況,寫在了下面
            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{//上面提到的 三種情況 均不滿足說明我們需要將消息插入消息隊列中的某個位置(在消息頭之後)
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {// 通過一個死循環來尋找消息插入的位置(其實就是通過時間來判斷的)
                    prev = p;// 注意每循環一次 prev 指針都會指向當前的 p 指向的那個消息
                    p = p.next;// 這裏移動 p 的位置到它的下一個消息,而此時 prev 仍然指向 p 原來的位置
                    if (p == null || when < p.when) {
                        //如果到了消息的隊尾或者找到了比我們要發送消息的時間晚的那個消息就退出循環
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;// 將我們要發送的消息放入 prev 和 當前 p 所指向的消息中間的位置
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

if (p == null || when == 0 || when < p.when) {//這三種情況看下面的分析
                // New head, wake up the event queue if blocked.

以下三種情況均需要把我們要發送的這個消息放在消息隊列的頭部

p==null  表示消息隊列爲空

when=0 表示需要立刻發送該消息

when<p.when 表示該消息發送的時間早於頭部的消息

好了,代碼中的註釋已經很詳細,到此分析就結束了,歡迎各路大神批評指正!

 

 

 

 

 

 

 

 

 

 

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