Handler---4部曲---1. 总体流程
Handler---4部曲---2. ThreadLocal 存储主流程
Handler---4部曲---3. MessageQueue队列
Handler---4部曲---4.细节补充
本章内容
MessageQueue队列.png一. 数据结构
MessageQueue数据结构.pngMessageQueue 3个成员变量
ArrayList<IdleHandler> mIdleHandlers --->
boolean mBlocked; --->next()是否阻塞 标记
Message mMessages; --->队列头
Message 3个成员变量
Handler target; //当前handler
long when; //消息延迟时间
Message next;//下一个消息
二. 消息分类
2.1 同步消息
2.2 异步消息
2.3 同步屏障消息 --->撤销屏障removeSyncBarrier()
2.4 空闲消息
三. 4种消息的添加方式
MessageQueue消息添加方式.png3.1 同步消息
enqueueMessage(Message msg, long when) 添加
boolean enqueueMessage(Message msg, long when) {
//用此方法添加到队列, msg一定要给target赋值
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {
msg.when = when;
Message p = mMessages;
//如果 首次进来 || 时间=0 || 当前时间<队列头的时间
//就把当前消息加到队列头
if (p == null || when == 0 || when < p.when) { //
msg.next = p;
mMessages = msg;
} else {
//把当前msg按照when 从小到大插入队列中
Message prev;
for (;;) {
prev = p; //
p = p.next;
if (p == null || when < p.when) {
break;
}
}
//此时 prev.when<msg.when<p.when
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
}
return true;
}
总结:把msg消息按时间顺序, 从小到大添加到队列中.
3.2 异步消息
和同步消息差不多, 只是把msg标记为异步.
msg.setAsynchronous(true)
MessageQueue.enqueueMessage(msg, 时间xxx)
3.3 同步屏障消息
//添加同步屏障消息
int token = MessageQueue.postSyncBarrier();
//移除同步屏障消息
removeSyncBarrier(token);
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
synchronized (this) {
//获取Message 对象
final Message msg = Message.obtain();
msg.when = when; //时间赋值---当前时间
// 以下的操作,和普通消息一样,按时间顺序 小到大排列
// 最后msg就是队列头.
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;
}
}
总结:
msg内部创建,也是按时间顺序进行排列的,
msg.target = null
msg.when = 当前时间
3.4 空闲消息
将消息添加到mIdleHandlers集合中
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
四. next()消息处理
MessageQueue next出队流程.png Message next() {
//mIdleHandlers集合数量
int pendingIdleHandlerCount = -1;
//阻塞休眠时间
int nextPollTimeoutMillis = 0;
for (;;) {
//阻塞队列 nextPollTimeoutMillis休眠时间
// -1 一直休眠, 等待唤醒
// 0 不休眠, 马上执行
// 大于0,休眠时间
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//判断是否有异步消息, 如果有,循环队列, 取出异步消息
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//注意:如果异步消息 的时间 > 当前时间, 则会一直等待, 其它消息得不到执行, 直到异步消息执行完为止.
//此时msg代表取出的消息
if (msg != null) { //有消息
if (now < msg.when) { //没有到执行时间
//休眠时间 = (时间差,Integer.MAX_VALUE)中的小值.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 马上执行消息
mBlocked = false; //标记线程不阻塞
if (prevMsg != null) { //异步消息时
prevMsg.next = msg.next;
} else { //同步消息时,队列头=下一个msg
mMessages = msg.next;
}
msg.next = null;
return msg;
}
} else {
// 如果没有消息,休眠时间--->一直休眠
nextPollTimeoutMillis = -1;
}
//是否退出(下一篇会讲)
if (mQuitting) {
dispose();
return null;
}
//>>>>>>>>>>>>>>>下面是处理 空闲消息 mIdleHandlers>>>>>>>>>>>>>>>>>>>>>>>>>>
if (pendingIdleHandlerCount < 0 //首次进入
//&& (没有消息 || 当前时间 < 队列头时间)
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
//没有空闲消息处理
if (pendingIdleHandlerCount <= 0) {
mBlocked = true; //标记,线程阻塞
continue;
}
//空闲消息List 转 数组
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
//循环处理空闲消息
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // 释放数组内存
boolean keep = false;
try {
// //返回false才会删除任务, 否则重复执行
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
//重置变量
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
Message消息处理:
- 首先获取队列头:Message msg = mMessages;
- 判断是否有同步屏障的消息. 如果有,会循环队列, 去找异步消息msg
①. 如果有异步消息,msg = 异步消息
②. 如果没有异步消息,msg==null. - 如果msg==null, 线程进入休眠,nextPollTimeoutMillis = -1;
- 如果 msg!=null;
①. 当前时间 < msg.when, nextPollTimeoutMillis(休眠时间) = msg.when-当前时间
②. 当前时间 >= msg.when,取出msg给loop去处理
------>同步消息时,队列头=下一个msg, mMessages = msg.next
空闲消息处理:
没有msg消息处理的时候,才会处理空闲消息
- mIdleHandlers集合 转 数组
- 遍历数组 处理任务
- 任务返回false时, 才会从mIdleHandlers集合移除任务.
- 重置变量
endingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
网友评论