【原創】源碼角度分析Android的訊息機制系列(四)——MessageQueue的工作原理

來源:互聯網
上載者:User

標籤:理解   size   live   oid   pat   oci   exce   for   calling   

ι 著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

 

 MessageQueue,主要包含2個操作:插入和讀取。讀取操作會伴隨著刪除操作,插入和讀取對應的方法分別為enqueueMessage和next,其中enqueueMessage的作用是往訊息佇列中插入一條訊息,而next的作用是從訊息佇列中取出一條訊息並將其從訊息佇列中移除。雖然MessageQueue叫訊息佇列,但是它的內部實現並不是用的隊列,實際上它是通過一個單鏈表的資料結構來維護訊息列表,單鏈表在插入和刪除上比較有優勢。

 

先看MessageQueue的定義:

/** * Low-level class holding the list of messages to be dispatched by a * {@link Looper}.  Messages are not added directly to a MessageQueue, * but rather through {@link Handler} objects associated with the Looper. *  * <p>You can retrieve the MessageQueue for the current thread with * {@link Looper#myQueue() Looper.myQueue()}. */public final class MessageQueue

通過源碼我們可以知道,MessageQueue維護了一個訊息列表。Messgae並不是直接添加到MessageQueue中,而是通過和Looper相關聯的Handler來添加的。在當前線程中可以通過調用Looper.myQueue()方法來擷取當前線程的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的源碼中定義了一個成員屬性target,其類型為Handler。由上面enqueuMessage的源碼,我們可以看到,當Message沒有處理其的Handler或該Message正在被處理的時候,都不能正常進入MessageQueue,這一點也是很容易理解的。當線程處於死亡狀態的時候,Message會被回收掉,而不再進入該線程對應的MessageQueue中。否則,一切正常,enqueMessage就執行單鏈表的插入操作,將Message插入到MessageQueue中。

 

 再來看MessageQueue的next讀取操作:

    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.                                  }                 // 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;        }    }

通過源碼我們可以知道,next方法會不停地去迴圈讀取MessageQueue中的Message。若MessageQueue中沒有訊息了,則next方法會暫時阻塞( nextPollTimeoutMillis = -1)。有訊息到來時,next會繼續讀取訊息,返回該訊息,並將其從單鏈表中移除。

【原創】源碼角度分析Android的訊息機制系列(四)——MessageQueue的工作原理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.