作为一个Android程序员,Handler一定都很熟悉了,这篇文章就不对Handler的整个流程做一个讲解了,主要讲解一下Handler从MessageQueue中是如何取出将要执行的消息的。
大家都知道Handler是将Message添加到MessageQueue中的,添加Message用的是MessageQueue的enqueueMessage方法。我们直接看下代码,代码中去除了一些部分,我们来看主要逻辑。
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
...
//这里先给msg设置状态,并将演示操作的时间复制给msg中的when
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
//这里先判断一下,新msg的when和队列开头的msg(后面用p代替)的when的大小,如果
//新msg的when小于p的when或者新msg的when为0(证明不需要延时)或者说p为null
//(队列中还没有消息),说明新msg需要马上或者说在p前面执行,这个时候就讲新msg加入到
//队列的开头
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
//设置是否需要唤醒
needWake = mBlocked;
} else {
//这里判断一下消息队列是否需要唤醒,因为有的消息需要延时执行,所以可能存在队列阻塞,
//等待延时消息到达时间。这里三个判断意思就是:当前队列正在阻塞,并且新msg是异步消息,
//当前消息是一个屏障消息,那么这里就需要唤醒队列。
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//如果不满足以上条件,证明新msg需要在p的后面来执行,所以这里用一个循环。根据when的
//大小找出新msg合适的位置,就是为了让新msg根据放到队列中when比自己的when大的msg前面
//这样就可以先取出来执行。这里新msg的位置一定是在p后面的。
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;
}
//如果needWake为true,那么就会调用nativeWake方法唤醒队列的阻塞
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
复制代码
这样在Message就放入到了MessageQueue中。
下面当Handler取消息的时候,其实是用Looper来取出消息的,Looper中有一个for循环,一直不断的从MessageQueue中取出消息,具体的获取Message方法是在MessageQueue的next方法中:
Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
...
//这里根据nextPollTimeoutMillis参数来判断是否需要阻塞(前面的唤醒就是唤醒这里)
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是一个屏障消息,通过循环找到最新的异步消息
//异步消息是优先执行的消息,一般界面绘制相关的msg就会是异步消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// 判断一下msg是否有延时操作,如果有的话奖需要等待的时间赋值给
//nextPollTimeoutMillis,最上面就会根据nextPollTimeoutMillis
//的值来判断是否需要阻塞
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//如果msg不需要延时,则直接从队列中取出。执行后面的操作。
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse();
return msg;
}
} else {
nextPollTimeoutMillis = -1;
}
if (mQuitting) {
dispose();
return null;
}
...
if (pendingIdleHandlerCount <= 0) {
//如果没有任何消息可以执行,设置mBlocked为true,证明队列处于阻塞状态
//下一个新消息进来的时候需要唤醒列队。
mBlocked = true;
continue;
}
}
...
}
}
复制代码
到这里取消息的逻辑就完成了,主要是想记录一下延时消息是如何处理的,以及队列的阻塞和唤醒是有怎样的逻辑。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END