结合源码分析Handler还是可以异步的。首先介绍下 Android 消息处理机制相关的几个类:
1,Message:消息实体;
2,MessageQueue:消息队列;
3,Looper:消息循环体;
4,Handler:消息处理;
消息处理的机制,开始于 Looper.prepare(),Looper.loop(),那看看 Looper.loop() 的源码:
public static void loop() {
//省略代码
final MessageQueue queue = me.mQueue;
for (;;) {
// 从MessageQueue拿到一个Message,queue.next()里面会阻塞cpu
Message msg = queue.next();
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//省略代码
// msg.target 实际就是 Handler实例,dispatchMessage处理消息
msg.target.dispatchMessage(msg);
//省略代码
msg.recycleUnchecked();
}
}
有两个关键代码:一个 queue.next(),一个 msg.target.dispatchMessage(msg),先看 Handler.dispatchMessage() 方法:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//如果Message.callback不空,实际也就是有Runnable,那么会直接运行它的run方法;
handleCallback(msg);
} else {
if (mCallback != null) {
// 如果new Handler的时候,传了Callback,会调用Callback.handleMessage
if (mCallback.handleMessage(msg)) {
return;
}
}
//Message没有Runnable,Handler没有Callback,或者Callback.handleMessage 返回false,才会调用Handler自己的handleMessage
handleMessage(msg);
}
}
接下来看 MessageQueue.next() 方法:
Message next() {
for (;;) {
//省略代码
// @1
// native层阻塞cpu
nativePollOnce(ptr, nextPollTimeoutMillis);
//省略代码
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// @2
// msg.target为空的情况,只有MessageQueue.enqueueSyncBarrier
// msg.isAsynchronous 只能结合 Barrier 使用,也就是说就算有异步的消息,但是没有设置 Barrier,也是没效果的。
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// @3
//有消息,但是还没到时间,最后转到 继续阻塞cpu(也就是上面的注释@1)
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
mBlocked = false;
if (prevMsg != null) {
// @4
// prevMsg不空,mMessages是不会变的,所以如果有Barrier,会始终尝试去拿异步消息(也就是上面的注释@2)
// 所以记得设置了Barrier,要对应的移除掉它,调用 MessageQueue.removeSyncBarrier
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
return msg;
}
} else {
nextPollTimeoutMillis = -1;
}
//省略代码
}
// @5
// 消息队列空闲的时候,也就是有消息但是还没到时间,或者没有消息的时候,会调用IdleHandler.queueIdle()
// 可以通过 MessageQueue.addIdleHandler方法添加
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null;
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
//省略代码
}
}
为什么 msg.target 为空的情况,只有 MessageQueue.enqueueSyncBarrier?
因为正常上 Handler 的 sendMessage 或者是 Message 的 sendToTarget ,实际最后都是走到
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("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;
}
从上面代码就可以看出,正常的 sendMessage 如果 target 为空,会抛出异常的。
反而 MessageQueue.enqueueSyncBarrier:
int enqueueSyncBarrier(long when) {
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
从上面代码可以看出,Barrier也就是个Message,是没有target的。
怎么让 msg.isAsynchronous 呢?
有两种方式:
1,Message的方法setAsynchronous();
2,Handler的构造方法,可以传入 async 参数;
public Handler(Handler.Callback callback, boolean async) {
//省略代码
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
// Handler的sendMessage 会把 msg 赋值成 Asynchronous
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
总结:
1,消息队列循环执行,不一定是完全按照时间串行执行的,是可以有异步消息的。
2,异步消息 必须结合 Barrier 使用,也就是说就算有异步消息,但是没有设置 Barrier,也是没效果的。
3,设置了Barrier,要对应的移除掉它,否则同步消息再也不会被处理。