前言
本系列文章,將分享與Handler相關(guān)的知識,包括Handler的結(jié)構(gòu),運作流程,各個類的作用、之間的關(guān)系
內(nèi)容提要
本篇文章將分析MessageQueue的作用,以及主要的方法
重要屬性
//native層消息隊列的指針地址
private long mPtr;
// 是否允許退出消息隊列
private final boolean mQuitAllowed;
// 消息隊列尾部指針,無論做什么操作,最后都會將它指向尾部節(jié)點
Message mMessages;
內(nèi)部類/接口
/**
* Callback interface for discovering when a thread is going to block waiting for more messages.
*/
public static interface IdleHandler {
/**
* Called when the message queue has run out of messages and will now wait for more.
* Return true to keep your idle handler active, false to have it removed.
* This may be called if there are still messages pending in the queue, but they are all scheduled to be dispatched after the current time.
*/
boolean queueIdle();
}
native方法
private native static void nativeDestroy(long ptr);
銷毀消息
private native static boolean nativeIsPolling(long ptr);
消息隊列是否正在進行輪詢
重要方法
boolean enqueueMessage(Message msg, long when)
消息入列
- 1.下面的代碼,除了說明了消息的入列規(guī)則(請看注釋),還表明了消息隊列的結(jié)構(gòu),消息隊列的排布規(guī)則是由隊列頭到隊列尾,消息發(fā)送的優(yōu)先程度依次遞減,優(yōu)先從隊列尾部取消息(題外話:這樣其實與隊列(Queue)的定義不符,隊列要求只從尾部加入,頭部刪除,所以我覺得消息隊列的“隊列”,更多屬于象征意義上的,實際上,它是一個單向鏈表)
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;
//是否需要喚醒native隊列
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// 如果
// 1.當前message指針為空(message指針總是指向隊尾,說明消息隊列為空)
// 2.when==0(說明這是一個想立即發(fā)送的message)
// 3.when < p.when(即這個消息要比message指針指向的消息更早地被發(fā)送)
// 則把傳入的message放入隊尾
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
// 在next()方法里面,mBlocked可能被設(shè)為true,也就是隊列阻塞了
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.
// 在Handler分析里說過,
// 1.正經(jīng)通過Handler發(fā)送的Message,必然有target
// 2.API<28 的情況下,理論上Message必然是同步的
// 所以在一般情境下,這里needWake的值就取決于mBlocked
// 在next()方法里面,mBlocked可能被設(shè)為true,也就是隊列阻塞了
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (; ; ) {
prev = p;
p = p.next;
// p == null表示已經(jīng)到隊列的頭了
// when < p.when 表示p對應(yīng)的消息的到期時間已經(jīng)晚于要入列的msg了
// 任一情況,都將要入列的msg插入
if (p == null || when < p.when) {
break;
}
//只要在插入的節(jié)點至隊列尾部的任一節(jié)點是異步的,都不需要喚醒native隊列(其實我也沒搞懂是啥意思)
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 next()
取出下一條到期的Message
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.
// native消息隊列的指針
final long ptr = mPtr;
// ptr == 0 ,說明沒有消息了
// 這里是否說明,入列的消息其實會被存放到native層(至少是存一個副本)?
// 但是并沒有觀察到有相關(guān)的代碼
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
//下一次輪詢的時間間隔
int nextPollTimeoutMillis = 0;
for (; ; ) {
if (nextPollTimeoutMillis != 0) {
// Binder通信機制,知識盲區(qū),研究了再補
Binder.flushPendingCommands();
}
//執(zhí)行一次輪詢,取出待發(fā)送的消息,如果沒有可用的消息,這里會阻塞,直到被重新喚醒
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;
// 一般情境下,不存在沒有target的msg,所以這部分大概率不走
if (msg != null && msg.target == null) {
//msg不為空,但是該msg不持有Handler
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
//如果msg不為空且不是異步的,取下一個
//也就是說需要找出來一個異步msg,或者到隊列最后
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
// 1.正常的msg
// 2.最終找到一個異步的msg
if (now < msg.when) {
// 如果當前msg還沒到發(fā)送時間,把時間差記下來,下一次輪詢會按照這個時間差等待
// 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;
//取出msg
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;
}
}
void quit(boolean safe)
退出消息隊列
- 1.這里會判斷是否允許退出(主線程的消息隊列就是不允許退出的)和是否已經(jīng)在執(zhí)行退出了
- 2.根據(jù)是否安全退出,會移除所有未被發(fā)送的Message/移除所有Message
- 3.最后調(diào)用了一個native方法nativeWake(),看資料說是喚醒底層的隊列,目前還沒看native層的源碼,下回分解
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
private void removeAllFutureMessagesLocked()
移除所有未到期的message
- 1.如果隊列尾部的指針已經(jīng)是未到期(p.when > now),那么按照消息隊列的排隊規(guī)則,后面的消息肯定都沒有到期,直接removeAllMessagesLocked()全部移除
- 2.找出到期的第一個msg,后面全部移除
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
for (; ; ) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
private void removeAllMessagesLocked()
很簡單,全部消息移除
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
private void dispose()
- 1.處理native層的消息隊列
- 2.這個方法必須在looper線程或者在finalizer方法里面調(diào)用
- 3.mPtr是native層消息隊列的指針,通過調(diào)用native方法nativeDestroy(mPtr),銷毀消息
private void dispose() {
if (mPtr != 0) {
nativeDestroy(mPtr);
mPtr = 0;
}
}
本篇內(nèi)容到此結(jié)束,感謝收看~~