Android源碼閱讀之MessageQueue

MessageQueue在消息機制中主要負責維護Message的鏈表結構,以及當有新Message進來時向Looper提供新Message,MessageQueue字義上看起來是消息隊列的意思,但其數據結構其實是一個單鏈表的結構,從Message類的定義可以看出,裏面有一個變量,指向了下一個Message

// sometimes we store linked lists of these things

/*package*/ Message next;

接下來,一起來看下MessageQueue中幾個重要的方法

enqueueMessage

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

                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;

}

此方法是將一個Message添加到Message鏈表中去,會先對message進行常規判斷,message的handler是否爲空,是否處於可使用的狀態中,以及當前的消息機制是否被停止(由looper調用),當停止時,插入消息失敗

接下來就是鏈表的插入操作,先判斷是否存在表頭,一開始mMessages是爲空的,所以會將當前消息作爲頭部,mMessages作爲當前消息的next

next()

next方法中是一個死循環 不斷從消息鏈表中查詢是否有可用狀態的新消息加入,如果有,則返回給Looper

Message next() {

    // Return here if the message loop has already quit and been disposed.

    // This can happen if the application tries to restart a looper after quit

    // which is not supported.

    final long ptr = mPtr;

    if (ptr == 0) {

        return null;

    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration

    int nextPollTimeoutMillis = 0;

    for (;;) {

        if (nextPollTimeoutMillis != 0) {

            Binder.flushPendingCommands();

        }

        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {

            // Try to retrieve the next message.  Return if found.

            final long now = SystemClock.uptimeMillis();

            Message prevMsg = null;

            Message msg = mMessages;

            if (msg != null && msg.target == null) {

                // Stalled by a barrier.  Find the next asynchronous message in the queue.

                do {

                    prevMsg = msg;

                    msg = msg.next;

                } while (msg != null && !msg.isAsynchronous());

            }

            if (msg != null) {

                if (now < msg.when) {

                    // Next message is not ready.  Set a timeout to wake up when it is ready.

                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);

                } else {

                    // Got a message.

                    mBlocked = false;

                    if (prevMsg != null) {

                        prevMsg.next = msg.next;

                    } else {

                        mMessages = msg.next;

                    }

                    msg.next = null;

                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);

                    msg.markInUse();

                    return msg;

                }

            } else {

                // No more messages.

                nextPollTimeoutMillis = -1;

            }

            // Process the quit message now that all pending messages have been handled.

            if (mQuitting) {

                dispose();

                return null;

            }

            // If first time idle, then get the number of idlers to run.

            // Idle handles only run if the queue is empty or if the first message

            // in the queue (possibly a barrier) is due to be handled in the future.

            if (pendingIdleHandlerCount < 0

                    && (mMessages == null || now < mMessages.when)) {

                pendingIdleHandlerCount = mIdleHandlers.size();

            }

            if (pendingIdleHandlerCount <= 0) {

                // No idle handlers to run.  Loop and wait some more.

                mBlocked = true;

                continue;

            }

            if (mPendingIdleHandlers == null) {

                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];

            }

            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);

        }

        // Run the idle handlers.

        // We only ever reach this code block during the first iteration.

        for (int i = 0; i < pendingIdleHandlerCount; i++) {

            final IdleHandler idler = mPendingIdleHandlers[i];

            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;

            try {

                keep = idler.queueIdle();

            } catch (Throwable t) {

                Log.wtf(TAG, "IdleHandler threw exception", t);

            }

            if (!keep) {

                synchronized (this) {

                    mIdleHandlers.remove(idler);

                }

            }

        }

        // Reset the idle handler count to 0 so we do not run them again.

        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered

        // so go back and look again for a pending message without waiting.

        nextPollTimeoutMillis = 0;

    }

}

這裏看不太懂啊 搬運一下其他大佬的見解

獲取消息:

1.首次進入循環nextPollTimeoutMillis=0,阻塞方法nativePollOnce(ptr, nextPollTimeoutMillis)會立即返回

2.讀取列表中的消息,如果發現消息屏障,則跳過後面的同步消息,總之會通過當前時間,是否遇到屏障來返回符合條件的待處理消息

3.如果沒有符合條件的消息,會處理一些不緊急的任務(IdleHandler),再次進入第一步

加入消息:

1.加入消息比較簡單,按時間順序插入到消息鏈表中,如果是第一個那麼根據mBlocked判斷是否需要喚醒線程,如果不是第一個一般情況下不需要喚醒(如果加入的消息是異步的需要另外判斷)

到這裏其實關於MessageQueue已經分析的差不多了,其中有兩個native方法沒有涉及到分別是nativePollOnce,nativeWake,其實之前結論已經給出了,兩個方法都會傳入mPtr,在native層對應的是NativeMessageQueue的引用地址。

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