使用Handler的postDealy後消息隊列會有什麼變化? 總結

MessageQueue裏的消息會以時間順序(執行的先後順序)來排序,使用Handler的postDealy後,MessageQueue裏的消息會進行重新排序。
根據源碼一步步分析:

public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
    return sendMessageDelayed(getPostMessage(r), delayMillis);
}

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

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
    ......
    return enqueueMessage(queue, msg, uptimeMillis);
}

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    ......
    return queue.enqueueMessage(msg, uptimeMillis);
}

根據調用一步一步走,最後會調用如下代碼:

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            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;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            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 {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {//這裏主要用於找出Message應該插入的位置
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {//如果時間小於消息時間,則找到位置
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                //將消息插入到剛剛找到的位置上
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

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

如上所示,首先會根據消息的時間(當前時間+延遲時間)與消息隊列裏面的消息的時間進行對比查找,找到需要插入的位置然後插入。在MessageQueue中,所有的Message是以鏈表的形式組織在一起。爲啥叫消息隊列,大概是因爲從MessageQueue有着隊列的性質,只能從隊首刪除,隊尾添加(MessageQueue不只是可以從隊尾添加)。在使用時都是通過Looper.loop()從消息隊列中取出消息,而且loop方法就是從MessageQueue的隊首開始取出消息。

總結

使用Handler的postDealy後消息隊列可能會進行重新排序。消息隊列裏消息按執行先後時間進行排序,先執行的在前,後執行的在後。postDealy發送的消息會根據延遲時間與消息隊列裏存在的消息的執行時間進行比較,然後尋找插入位置插入消息。

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