消息类型
1. 屏障消息
特点
msg.target为空
相关方法
添加屏障
MessageQueue#postSyncBarrier
移除屏障
MessaageQueue#removeSyncBarrier
源码举例
//android.view.ViewRootImpl
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//添加屏障
//保证后续绘制UI的msg可以被优先执行
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
//...省略代码
}
}
void unscheduleTraversals() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
//移除屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
mChoreographer.removeCallbacks(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
}
}
2. 异步消息
特点
msg中flag&FLAG_ASYNCHRONOUS不为0
msg专门提供了两个方法
设置消息类型为异步消息
//android.os.Message
public void setAsynchronous(boolean async) {
if (async) {
flags |= FLAG_ASYNCHRONOUS;
} else {
flags &= ~FLAG_ASYNCHRONOUS;
}
}
设置判断消息类型是否是异步消息
//android.os.Message
public boolean isAsynchronous() {
return (flags & FLAG_ASYNCHRONOUS) != 0;
}
源码举例
//android.view.Choreographer
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
//callback加到链表中
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
//如果到了执行时间,或者过了执行时间,就立刻开始获取VSYNC信号
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
//如果还没到执行时间,就设定指定时间执行
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
//设置消息类型为异步消息
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
3. 同步消息
普通消息,无优先执行权。也即是非屏障消息,非异步消息。
整体逻辑
异步消息需要配合屏障消息使用才会生效。
Android中,系统也会大量使用handler进行线程间的通信。正常情况下,所有的消息按执行时间排序,以单链表的方式存于MessageQueue,但是,有些消息的优先级比较高(比如说屏幕的绘制),我们希望能在指定时间立即执行,就诞生了消息屏障+异步消息。
MessageQueue#next流程图
源码
//android.os.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 (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//进行休眠操作
//参数nextPollTimeoutMillis:
// 0:不需要休眠;
// -1:一直休眠,直到被唤醒;
// >0: 指定时间自动唤醒
//注意此处for循环,第一次进来nextPollTimeoutMillis必然为0,第二次、第三次for循环,nextPollTimeoutMillis可能为0/-1/大于0的值
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) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
//如果队首是屏障消息,遍历MessageQueue,找到最早的异步消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
//如果找到了msg
//对应两种情况:
//1. 队首不是屏障消息,那msg可能是同步消息,也可能异步消息,此时,不区分是同步还是异步,均按同步消息进行处理
//2. 队首是屏障消息,那msg必然是异步消息
if (now < msg.when) {
//如果找到的msg还没到执行的时间,那就计算一下休眠时间
//等待下一次for循环的时候进行休眠
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//如果已经到了msg的执行时间
mBlocked = false;
//把msg从链表中移除
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
//for循环结束,msg返回给looper,做下一步处理
return msg;
}
} else {
//如果没找到msg
//存在两种情况
//1. 队首不是屏障消息,那意味着MessageQueue里没有消息,链表是空
//2. 队首是屏障消息,表示队列里没有异步消息
//等下一次for循环,nativePollOnce一直休眠
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
//第一次计算IdleHandler的数量
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
//没有IdleHandler要处理,就外层的继续for循环
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
//遍历设置的IdleHandler
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 {
//执行IdleHandler#queueIdle方法
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
//IdleHandler#queueIdle方法返回false,表示该idlehandler只需要执行一次
//把该IdleHandler从列表里移除,下次不再执行
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
//走到这里,说明有IdleHandler,并且已经执行了一遍IdleHandler#queueIdle了
//那把nextPollTimeoutMillis置为0
//这样,在下次for循环时,不是直接休眠,而是再看看msg的情况(毕竟IdleHandler#queueIdle执行时间不定,可能出现IdleHandler#queueIdle执行完后,队首的消息状态已经发生了变化)
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
总结
- MessageQueue的数据结构是以执行时间排序的单向链表,表头的执行时间最小,最先被处理
- 如果MessageQueue的链表队首不是屏障消息,那链表里的异步消息与普通消息无异
- 如果屏障消息后面没有异步消息,那在屏障消息移除前,即使没有要执行的异步消息,同步消息(普通消息)都不会被执行(消费)