查看MessageQueue源码时看到一个没有没有听过的概念“同步屏障”,这个是什么概念?带着疑问一探究竟。
MessageQueue有这么一个方法
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
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;
}
}
这个方法向消息队列中插入了一个“特殊”的message,并返回一个token。为什么说它特殊,因为这个message的target==null。一般我们发送的message的target都是handler,查看Handler源码可以证实,不管使用post方法还是sendMessage方法都会调用到enqueueMessage。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
这个特殊的message有什么作用?具体作用从MessageQueue的next方法中可以看到
Message next() {
...
for (;;) {
...
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) {
// 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) {
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) {
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;
}
}
}
}
上面代码为从消息队列中取消息的方法,第11行的判断msg != null && msg.target == null可以看出,如果遇到target==null的message会在它后面消息中进行循环遍历,直到遍历到队尾或找到一个isAsynchronous()==true的消息,即异步消息。
遍历过程如下图
异步消息是什么?和平时我们使用的message有什么区别?
直观的解释就是isAsynchronous()==true的消息,和我们平时使用的message只是一个标志位的差别,仅此而已。
要想创建一个异步消息有两种方式:
方法一:
Message msg = Message.obtain();
msg.setAsynchronous(true);
不过setAsynchronous这个方法是api22之后才加入的
方法二:
创建Handler时, 将async参数设置为true
public Handler(boolean async){...}
public Handler(Callback callback, boolean async){...}
public Handler(Looper looper, Callback callback, boolean async){...}
不过这个三个构造函数都被注解为@hide,不能被我们调用。
所以一旦消息队列中插入了msg.target == null的消息后就形成了一个屏障,将其后的同步消息都屏蔽掉,只有异步消息会被执行到,这样也就为我们创造了一个提高message优先级的方法。
不过在使用postSyncBarrier时一定要和removeSyncBarrier成对出现,不然会导致同步消息在一直无法被执行的情况。
欢迎关注公众号:从技术到艺术