子线程维护的Looper,消息队列没有消息时的处理方方案怎么处理
首先调用Looper的loop(),在loop()中,会去一直从MessageQueue中获取message.
Message msg = queue.next();
继续跟踪MessageQueue的next方法;
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
nativePollOnce(ptr, nextPollTimeoutMillis); //1
synchronized (this) {
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) {
.......
} else {
// No more messages.
nextPollTimeoutMillis = -1; //2
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
} //3
......
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
} // 4
}
}
}
主要分析上面的1、2、3、4处。
从上面可以看到,当没有message的时候,也就是会走2处,会把nextPollTimeoutMillis = -1,
当nextPollTimeoutMillis = -1时,走到4的时候,此时会结束本次循环,继续下次的循环,然后走到1处,
private native void nativePollOnce(long ptr, int timeoutMillis);
当nativePollOnce()的timeoutMillis参数取值如下:
0,立即返回,没有阻塞;
负数,一直阻塞,直到事件发生;
正数,表示最多等待多久时间;
而我们传入的nextPollTimeoutMillis = -1,此时会一直阻塞。
在这里面采用的时==epoll机制==。
什么时候会唤醒
当我们调用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) {
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;//1
} else {//3
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);
}//2
}
return true;
}
我们可以知道mBlocked赋值是在next方法中,当获取到一个message的时候,mBlocked = false,表明此时没有阻塞,不需要唤醒。
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
pendingIdleHandlerCount时用来统计IdleHandler的数量,当没有IdleHandler在运行,说明 Loop正在阻塞中,此时mBlocked = true;
从1我们可以知道,p == null || when == 0 || when < p.when表示此时队列中没有消息,此时添加的消息是第一个,那next()中的此时是阻塞的,此时mBlocked = true,则needWake = true,插入成功之后,走2处代码,则去唤醒。
当走3处的代码的时候,表明此时是有message的,我们则根据执行时间的先后来进行插入。此时needWake = mBlocked && p.target == null && msg.isAsynchronous();
mBlocked = false,则needWake = false;最后不走后面唤醒的逻辑。
如果一直不插入消息,我们该怎么唤醒?
调用Loop的quit();
public void quit() {
mQueue.quit(false);
}
然后会调用MessageQueue的quit();
void quit(boolean safe) {
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
调用quit()是,将mQuitting = true;然后调用nativeWake(mPtr)进行唤醒。
唤醒之后,再看next(),
if (mQuitting) {
dispose();
return null;
}
因为在quit()中已经将mQuitting置为true,此时则会返回null.
然后再Loop的loop()中的到的message = null.
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
可以看到当msg == null时,直接返回。