本文主要內(nèi)容:
從Looper源碼的角度,分析如何終止消息循環(huán)渣淤,以及終止消息循環(huán)的兩種方式的不同赏寇。
一、Looper終止消息循環(huán)
Looper終止消息循環(huán)有兩種方法价认,quit()和quitSafely()
Looper的quitSafely()方法:
public void quitSafely() {
mQueue.quit(true);
}
Looper的quit()方法:
public void quit() {
mQueue.quit(false);
}
二者共同調(diào)用了MessageQueue的quit(boolean safe)方法:
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);
}
}
兩者的區(qū)別就在于其中的這幾句:
if (safe) {
removeAllFutureMessagesLocked(); //清空延遲消息
} else {
removeAllMessagesLocked(); //清空所有消息
}
removeAllMessagesLocked方法嗅定,該方法的作用是把MessageQueue消息池中所有的消息全部清空,無論是延遲消息還是非延遲消息用踩。(延遲消息是指通過sendMessageDelayed或通過postDelayed等方法發(fā)送的需要延遲執(zhí)行的消息)
removeAllFutureMessagesLocked方法渠退,只會清空MessageQueue消息池中所有的延遲消息,并將消息池中所有的非延遲消息派發(fā)出去讓Handler去處理脐彩,quitSafely相比于quit方法安全之處在于清空消息之前會派發(fā)所有的非延遲消息碎乃。
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) { //延遲執(zhí)行的消息
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() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
最后,當(dāng)Looper.loop繼續(xù)從MessageQueue中獲取消息時惠奸,發(fā)現(xiàn)獲取的是空荠锭,消息循環(huán)就終結(jié)了。這時候再通過Handler調(diào)用sendMessage或post等方法發(fā)送消息時均返回false晨川,表示消息沒有成功放入消息隊列MessageQueue中证九,因為消息隊列已經(jīng)退出了删豺,具體分析見下面:
MessageQueue中插入消息的代碼如下:
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("MessageQueue", 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;
}
其中這一句:
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
msg.recycle();
return false;
}
mQuitting表示已經(jīng)退出。這個時候無法插入消息愧怜,返回false呀页。
參考:
Looper源代碼:
MessageQueue源代碼:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/os/MessageQueue.java#MessageQueue.quit%28boolean%29