「这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战」。
MessageQueue数据结构
MessageQueue的底层实现是单链表,我们可以查看源代码
MessageQueue的每个节点是Message型数据,继续查看Message的结构
会发现里面有个next引用,由此可知MessageQueue应该是链表结构
Message的主要方法
enqueueMessage
这个方法的目的也很简单,就是将Message插入到单链表中,其它的都是对msg进行一些规范检测,比如msg的target不能为空,如果为空msg不知道将要交给哪个线程(handler)进行处理
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
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;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
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.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
next方法
next方法会取出队列中的消息并且把节点删除
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.
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();//2
}
...
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;//1
}
// Process the quit message now that all pending messages have been handled.
...
}
}
对于next这里省略了一些代码,根据这段可以发现如果当消息队列为空时,nextPollTimeoutMullis会赋值为-1,下次循环时会调用Binder.flushPendingCommands(),我们进入这个方法,去看下这个方法的简介
- Flush any Binder commands pending in the current thread to the kernel
- driver. This can be
- useful to call before performing an operation that may block for a long
- time, to ensure that any pending object references have been released
- in order to prevent the process from holding on to objects longer than
- it needs to.
个人理解是将当前进程的所有Binder命令刷入内核,之所以要全部刷入内核是因为当前message已经全部处理,当前线程即将进入阻塞状态,所以需要在这里将所有的binder任务进行提交。