Handler系列--MessageQueue
2019-03-25 本文已影响0人
小斌_bingor
前言
本系列文章,将分享与Handler相关的知识,包括Handler的结构,运作流程,各个类的作用、之间的关系
内容提要
本篇文章将分析MessageQueue的作用,以及主要的方法
重要属性
//native层消息队列的指针地址
private long mPtr;
// 是否允许退出消息队列
private final boolean mQuitAllowed;
// 消息队列尾部指针,无论做什么操作,最后都会将它指向尾部节点
Message mMessages;
内部类/接口
/**
* Callback interface for discovering when a thread is going to block waiting for more messages.
*/
public static interface IdleHandler {
/**
* Called when the message queue has run out of messages and will now wait for more.
* Return true to keep your idle handler active, false to have it removed.
* This may be called if there are still messages pending in the queue, but they are all scheduled to be dispatched after the current time.
*/
boolean queueIdle();
}
native方法
private native static void nativeDestroy(long ptr);
销毁消息
private native static boolean nativeIsPolling(long ptr);
消息队列是否正在进行轮询
重要方法
boolean enqueueMessage(Message msg, long when)
消息入列
- 1.下面的代码,除了说明了消息的入列规则(请看注释),还表明了消息队列的结构,消息队列的排布规则是由队列头到队列尾,消息发送的优先程度依次递减,优先从队列尾部取消息(题外话:这样其实与队列(Queue)的定义不符,队列要求只从尾部加入,头部删除,所以我觉得消息队列的“队列”,更多属于象征意义上的,实际上,它是一个单向链表)
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(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
//是否需要唤醒native队列
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// 如果
// 1.当前message指针为空(message指针总是指向队尾,说明消息队列为空)
// 2.when==0(说明这是一个想立即发送的message)
// 3.when < p.when(即这个消息要比message指针指向的消息更早地被发送)
// 则把传入的message放入队尾
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
// 在next()方法里面,mBlocked可能被设为true,也就是队列阻塞了
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.
// 在Handler分析里说过,
// 1.正经通过Handler发送的Message,必然有target
// 2.API<28 的情况下,理论上Message必然是同步的
// 所以在一般情境下,这里needWake的值就取决于mBlocked
// 在next()方法里面,mBlocked可能被设为true,也就是队列阻塞了
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (; ; ) {
prev = p;
p = p.next;
// p == null表示已经到队列的头了
// when < p.when 表示p对应的消息的到期时间已经晚于要入列的msg了
// 任一情况,都将要入列的msg插入
if (p == null || when < p.when) {
break;
}
//只要在插入的节点至队列尾部的任一节点是异步的,都不需要唤醒native队列(其实我也没搞懂是啥意思)
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;
}
Message next()
取出下一条到期的Message
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit which is not supported.
// native消息队列的指针
final long ptr = mPtr;
// ptr == 0 ,说明没有消息了
// 这里是否说明,入列的消息其实会被存放到native层(至少是存一个副本)?
// 但是并没有观察到有相关的代码
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
//下一次轮询的时间间隔
int nextPollTimeoutMillis = 0;
for (; ; ) {
if (nextPollTimeoutMillis != 0) {
// Binder通信机制,知识盲区,研究了再补
Binder.flushPendingCommands();
}
//执行一次轮询,取出待发送的消息,如果没有可用的消息,这里会阻塞,直到被重新唤醒
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;
// 一般情境下,不存在没有target的msg,所以这部分大概率不走
if (msg != null && msg.target == null) {
//msg不为空,但是该msg不持有Handler
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
//如果msg不为空且不是异步的,取下一个
//也就是说需要找出来一个异步msg,或者到队列最后
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
// 1.正常的msg
// 2.最终找到一个异步的msg
if (now < msg.when) {
// 如果当前msg还没到发送时间,把时间差记下来,下一次轮询会按照这个时间差等待
// 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;
//取出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();
return msg;
}
} else {
// 暂时没消息了,下一次轮询将会阻塞
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
// 如果正在退出队列,就销毁消息
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message in the queue (possibly a barrier) is due to be handled in the future.
// 这下面的代码是我不能理解的,貌似这部分是在异步消息的情况下才有作用的
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
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 {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
void quit(boolean safe)
退出消息队列
- 1.这里会判断是否允许退出(主线程的消息队列就是不允许退出的)和是否已经在执行退出了
- 2.根据是否安全退出,会移除所有未被发送的Message/移除所有Message
- 3.最后调用了一个native方法nativeWake(),看资料说是唤醒底层的队列,目前还没看native层的源码,下回分解
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
private void removeAllFutureMessagesLocked()
移除所有未到期的message
- 1.如果队列尾部的指针已经是未到期(p.when > now),那么按照消息队列的排队规则,后面的消息肯定都没有到期,直接removeAllMessagesLocked()全部移除
- 2.找出到期的第一个msg,后面全部移除
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
for (; ; ) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
private void removeAllMessagesLocked()
很简单,全部消息移除
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
private void dispose()
- 1.处理native层的消息队列
- 2.这个方法必须在looper线程或者在finalizer方法里面调用
- 3.mPtr是native层消息队列的指针,通过调用native方法nativeDestroy(mPtr),销毁消息
private void dispose() {
if (mPtr != 0) {
nativeDestroy(mPtr);
mPtr = 0;
}
}
本篇内容到此结束,感谢收看~~