时隔很久,重温Android消息机制,注意到这么两个东西
MessageQueue中的IdleHandler
看MessageQueue的源码发现,里面有个IdleHandler,声明如下
/**
* 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.
* 在当前线程变为空闲状态的时候执行,返回值代表是否保留该对象,如果返回false,那么该对象执行一次之后会被移除。
*/
boolean queueIdle();
}
它体现在MessageQueue.next()方法中。
Message next() {
// 省略部分代码
int pendingIdleHandlerCount = -1; // -1 only during first iteration
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// 省略部分代码
// 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);
}// end of synchronized (this)
// 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("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {// 由此可见,IdleHandler返回值的作用
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;
}
}
注意,这个IdleHandler的执行是每调用一次next()方法才会执行一次。
那么这个类的用处就显而易见了,当我们需要在线程空闲时执行一些操作的话,就可以利用这个类来做。使用方式如下
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
// do something
return false;
}
});
MessageQueue中的同步阻塞器
其实,同步阻塞器的本质依旧是一个Message,只不过它的target为空。它存在于消息队列中。同步阻塞器在插入后会返回一个token值,移除则是通过token值来进行。插入和移除的过程就不看了,它正常消息的插入移除很相似,都需要在消息队列中寻找一个合适的位置进行插入。看看它在消息队列中生效的地方。依旧看next()方法
Message next() {
// 省略部分代码
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) {
// msg.target == null 就代表该msg是同步阻塞器。正常通过Handler发送的消息msg.target都不可能为空的。
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
// 如果走到这里,则需要找一个异步的消息,Message的同步与异步的差别在这里就体现出来了,同步的消息会受阻塞器的影响,而异步消息不会。
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {// 这里的msg不可能是同步阻塞器。
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) {// 代表着得到的msg是异步消息
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// 省略部分代码
}// end of synchronized (this)
// 省略部分代码
}
}
这里我们要注意一点,同步阻塞器是无法阻塞在阻塞器生效前的同步消息。所以,当某个消息队列被阻塞器阻塞之后,要想执行操作,就需要你移除阻塞器或者发送异步消息。