/**
* Low-level class holding the list of messages to be dispatched by a
* {@link Looper}. Messages are not added directly to a MessageQueue,
* but rather through {@link Handler} objects associated with the Looper.
*
* <p>You can retrieve the MessageQueue for the current thread with
* {@link Looper#myQueue() Looper.myQueue()}.
*/
MessageQueue 类是 Android 系统中用于管理消息队列的一个低级类,它持有将要由 Looper 分发的消息列表。在 Android 的消息处理机制中,消息并不是直接添加到 MessageQueue 中的,而是通过与 Looper 相关联的 Handler 对象来添加的。
如果你想要获取当前线程(比如主线程)的 MessageQueue,你可以使用 Looper.myQueue() 方法。这个方法会返回与当前线程关联的 Looper 对象的 MessageQueue,如果当前线程没有 Looper,则会抛出 RuntimeException
// True if the message queue can be quit.
@UnsupportedAppUsage
private final boolean mQuitAllowed;
是否允许message queue退出。
@UnsupportedAppUsage
@SuppressWarnings("unused")
private long mPtr; // used by native code
native MessageQueue的指针变量
@UnsupportedAppUsage
Message mMessages;
Message Queue消息队列的队首指针,即消息队列最前面的元素。
@UnsupportedAppUsage
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
IdleHandler列表,用来记录需要进行callback回调的IdleHandler对象
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
mFileDescriptorRecords为存储文件描述符的map数据结构
private IdleHandler[] mPendingIdleHandlers;
处于等待的IdleHandler类型的数组
private boolean mQuitting;
消息队列正在退出
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
private boolean mBlocked;
指出是否next()被阻塞在了一个携带着非0超时参数的pollOnce() 上。
// The next barrier token.
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
@UnsupportedAppUsage
private int mNextBarrierToken;
表示下一个屏障(Barrier)的令牌(Token)
private native static long nativeInit();
用于初始化native层的message queue.
private native static void nativeDestroy(long ptr);
用于销毁native层的message queue
@UnsupportedAppUsage
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
等待timeoutMillis获取下一个消息
private native static void nativeWake(long ptr);
native部分,我们再讲
private native static boolean nativeIsPolling(long ptr);
native部分,我们再讲
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
native部分,我们再讲
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
@Override
protected void finalize() throws Throwable {
try {
dispose();
} finally {
super.finalize();
}
}
finalize() 方法是一个在对象被垃圾回收器回收之前调用的方法。
// Disposes of the underlying message queue.
// Must only be called on the looper thread or the finalizer.
private void dispose() {
if (mPtr != 0) {
nativeDestroy(mPtr);
mPtr = 0;
}
}
处理底层的message queue,即销毁native层的message queue。
/**
* Returns true if the looper has no pending messages which are due to be processed.
*
* <p>This method is safe to call from any thread.
*
* @return True if the looper is idle.
*/
public boolean isIdle() {
synchronized (this) {
final long now = SystemClock.uptimeMillis();
return mMessages == null || now < mMessages.when;
}
}
它检查循环器是否有任何即将被处理的挂起消息。如果循环器当前没有待处理的消息,或者所有待处理的消息的执行时间都晚于当前时间(即它们还没有到被处理的时机),则该方法返回 true,表示循环器当前是空闲的。
/**
* Add a new {@link IdleHandler} to this message queue. This may be
* removed automatically for you by returning false from
* {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
* invoked, or explicitly removing it with {@link #removeIdleHandler}.
*
* <p>This method is safe to call from any thread.
*
* @param handler The IdleHandler to be added.
*/
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
用于向消息队列中添加一个新的 IdleHandler。IdleHandler 是一个接口,用于在消息队列空闲时执行某些操作。通过添加 IdleHandler,开发者可以在消息队列没有待处理消息时执行自定义的空闲处理逻辑。
IdleHandler 可以通过在 IdleHandler.queueIdle() 方法中返回 false 来自动从消息队列中移除。这是因为在消息队列的空闲处理循环中,会遍历 mIdleHandlers 集合,并调用每个 IdleHandler 的 queueIdle() 方法。如果该方法返回 false,则表示该 IdleHandler 不再需要被调用,因此会从集合中移除。
/**
* Remove an {@link IdleHandler} from the queue that was previously added
* with {@link #addIdleHandler}. If the given object is not currently
* in the idle list, nothing is done.
*
* <p>This method is safe to call from any thread.
*
* @param handler The IdleHandler to be removed.
*/
public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}
可以通过调用 removeIdleHandler 方法来显式地从消息队列中移除 IdleHandler.
/**
* Returns whether this looper's thread is currently polling for more work to do.
* This is a good signal that the loop is still alive rather than being stuck
* handling a callback. Note that this method is intrinsically racy, since the
* state of the loop can change before you get the result back.
*
* <p>This method is safe to call from any thread.
*
* @return True if the looper is currently polling for events.
* @hide
*/
public boolean isPolling() {
synchronized (this) {
return isPollingLocked();
}
}
用于检查这个循环器(Looper)的线程当前是否在轮询(polling)以寻找更多的工作要做。这个方法是一个有用的信号,表明循环器仍在活跃状态,而不是在处理某个回调时被卡住.
private boolean isPollingLocked() {
// If the loop is quitting then it must not be idling.
// We can assume mPtr != 0 when mQuitting is false.
return !mQuitting && nativeIsPolling(mPtr);
}
该方法用于在同步或受保护的上下文中检查循环器(Looper)是否正在轮询(polling)事件。首先,方法检查 mQuitting 标志。如果 mQuitting 为 true,则表示循环器正在退出过程中,此时它不可能处于空闲轮询状态。因此,在这种情况下,方法会立即返回 false。其次,通过nativeIsPolling检查native层的循环器(Looper)是否正在轮询(polling)事件。只有java层和native层都处于轮询事件的状态,isPollingLocked才会返回true,否则返回false。
/**
* Adds a file descriptor listener to receive notification when file descriptor
* related events occur.
* <p>
* If the file descriptor has already been registered, the specified events
* and listener will replace any that were previously associated with it.
* It is not possible to set more than one listener per file descriptor.
* </p><p>
* It is important to always unregister the listener when the file descriptor
* is no longer of use.
* </p>
*
* @param fd The file descriptor for which a listener will be registered.
* @param events The set of events to receive: a combination of the
* {@link OnFileDescriptorEventListener#EVENT_INPUT},
* {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and
* {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks. If the requested
* set of events is zero, then the listener is unregistered.
* @param listener The listener to invoke when file descriptor events occur.
*
* @see OnFileDescriptorEventListener
* @see #removeOnFileDescriptorEventListener
*/
public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd,
@OnFileDescriptorEventListener.Events int events,
@NonNull OnFileDescriptorEventListener listener) {
if (fd == null) {
throw new IllegalArgumentException("fd must not be null");
}
if (listener == null) {
throw new IllegalArgumentException("listener must not be null");
}
synchronized (this) {
updateOnFileDescriptorEventListenerLocked(fd, events, listener);
}
}
它用于为文件描述符添加一个,以便在发生文件描述符相关事件时接收通知。如果该文件描述符之前已经有一个注册了,新的事件和将会取代之前注册的。每个文件描述符只能有一个:不能为同一个文件描述符设置多个。这意味着每次调用 addOnFileDescriptorEventListener 方法时,新设置的将替换之前的。
参数fd为FileDescriptor,events为OnFileDescriptorEventListener 中定义的事件掩码的组合,OnFileDescriptorEventListener为当发生文件描述符事件时要调用的。
/**
* Removes a file descriptor listener.
* <p>
* This method does nothing if no listener has been registered for the
* specified file descriptor.
* </p>
*
* @param fd The file descriptor whose listener will be unregistered.
*
* @see OnFileDescriptorEventListener
* @see #addOnFileDescriptorEventListener
*/
public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) {
if (fd == null) {
throw new IllegalArgumentException("fd must not be null");
}
synchronized (this) {
updateOnFileDescriptorEventListenerLocked(fd, 0, null);
}
}
这个方法 removeOnFileDescriptorEventListener 用于移除与指定文件描述符相关联的。如果没有为该文件描述符注册任何,那么这个方法不会进行任何操作。
private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events,
OnFileDescriptorEventListener listener) {
final int fdNum = fd.getInt$(); //1
int index = -1;
FileDescriptorRecord record = null;
if (mFileDescriptorRecords != null) {
index = mFileDescriptorRecords.indexOfKey(fdNum);
if (index >= 0) {
record = mFileDescriptorRecords.valueAt(index);
if (record != null && record.mEvents == events) {
return; //2
}
}
}
if (events != 0) {
events |= OnFileDescriptorEventListener.EVENT_ERROR;
if (record == null) {
if (mFileDescriptorRecords == null) {
mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>();
}
record = new FileDescriptorRecord(fd, events, listener);
mFileDescriptorRecords.put(fdNum, record);
} else {
record.mListener = listener;
record.mEvents = events;
record.mSeq += 1;
}
nativeSetFileDescriptorEvents(mPtr, fdNum, events);
} else if (record != null) {
record.mEvents = 0;
mFileDescriptorRecords.removeAt(index);
nativeSetFileDescriptorEvents(mPtr, fdNum, 0);
}
}
// Called from native code. // 1
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private int dispatchEvents(int fd, int events) {
// Get the file descriptor record and any state that might change.
final FileDescriptorRecord record;
final int oldWatchedEvents;
final OnFileDescriptorEventListener listener;
final int seq;
synchronized (this) {
record = mFileDescriptorRecords.get(fd);
if (record == null) {
return 0; // spurious, no listener registered // 2
}
oldWatchedEvents = record.mEvents;
events &= oldWatchedEvents; // filter events based on current watched set // 3
if (events == 0) {
return oldWatchedEvents; // spurious, watched events changed
}
listener = record.mListener;
seq = record.mSeq;
}
// Invoke the listener outside of the lock.
int newWatchedEvents = listener.onFileDescriptorEvents(
record.mDescriptor, events); // 4
if (newWatchedEvents != 0) {
newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR; // 5
}
// Update the file descriptor record if the listener changed the set of
// events to watch and the listener itself hasn't been updated since.
if (newWatchedEvents != oldWatchedEvents) {
synchronized (this) {
int index = mFileDescriptorRecords.indexOfKey(fd);
if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record
&& record.mSeq == seq) {
record.mEvents = newWatchedEvents;
if (newWatchedEvents == 0) {
mFileDescriptorRecords.removeAt(index); // 6
}
}
}
}
// Return the new set of events to watch for native code to take care of.
return newWatchedEvents;
}
@UnsupportedAppUsage
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) { // 1
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0; // 2
for (;;) { //17
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis); //4
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.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous()); // 5
}
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); // 6
} else {
// Got a message.
mBlocked = false; //18
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; // 8
}
// 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(); // 11
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true; //18
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); // 12
}
// 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(); //13
} 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; //15
// 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; //16
}
}
获取并返回队列中的下一个消息,如果队列为空或者当前没有准备好的消息,则会等待直到有消息到来。
void quit(boolean safe) {
if (!mQuitAllowed) {//1
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {//2
return;
}
mQuitting = true;
if (safe) {//3
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr); //4
}
}
/**
* Posts a synchronization barrier to the Looper's message queue.
*
* Message processing occurs as usual until the message queue encounters the
* synchronization barrier that has been posted. When the barrier is encountered,
* later synchronous messages in the queue are stalled (prevented from being executed)
* until the barrier is released by calling {@link #removeSyncBarrier} and specifying
* the token that identifies the synchronization barrier.
*
* This method is used to immediately postpone execution of all subsequently posted
* synchronous messages until a condition is met that releases the barrier.
* Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
* and continue to be processed as usual.
*
* This call must be always matched by a call to {@link #removeSyncBarrier} with
* the same token to ensure that the message queue resumes normal operation.
* Otherwise the application will probably hang!
*
* @return A token that uniquely identifies the barrier. This token must be
* passed to {@link #removeSyncBarrier} to release the barrier.
*
* @hide
*/
@UnsupportedAppUsage
@TestApi
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
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;
}
}
消息队列中发布一个同步屏障(synchronization barrier),暂停所有后续同步消息的执行,直到该屏障被移除。
/**
* Removes a synchronization barrier.
*
* @param token The synchronization barrier token that was returned by
* {@link #postSyncBarrier}.
*
* @throws IllegalStateException if the barrier was not found.
*
* @hide
*/
@UnsupportedAppUsage
@TestApi
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycleUnchecked();
// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
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;
}
boolean hasMessages(Handler h, int what, Object object) {
if (h == null) {
return false;
}
synchronized (this) {
Message p = mMessages;
while (p != null) {
if (p.target == h && p.what == what && (object == null || p.obj == object)) {
return true;
}
p = p.next;
}
return false;
}
}
检查一个给定的 Handler(h)是否在其消息队列中存在具有特定 what 值和可选的 object 对象的消息。
Object object:可选的,要检查的消息中携带的对象。如果为 null,则不对消息中的对象进行匹配检查。
boolean hasEqualMessages(Handler h, int what, Object object) {
if (h == null) {
return false;
}
synchronized (this) {
Message p = mMessages;
while (p != null) {
if (p.target == h && p.what == what && (object == null || object.equals(p.obj))) {
return true;
}
p = p.next;
}
return false;
}
}
与之前的 hasMessages 方法非常相似,但有一个关键的区别:在比较 object 和 p.obj 时,它使用了 equals 方法而不是简单的 == 操作符。这个改变在处理对象比较时非常重要,因为 == 操作符只比较对象的引用(即它们是否是同一个对象的引用),而 equals 方法则用于比较两个对象的内容是否相等。
boolean hasMessages(Handler h) {
if (h == null) {
return false;
}
synchronized (this) {
Message p = mMessages;
while (p != null) {
if (p.target == h) {
return true;
}
p = p.next;
}
return false;
}
}
检查给定的 Handler 是否在其消息队列中有待处理的消息,而不关心这些消息的具体内容或类型
void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
从消息队列中移除所有与给定 Handler (h)、what 值和 object 相匹配的消息
void removeEqualMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.what == what
&& (object == null || object.equals(p.obj))) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || object.equals(n.obj))) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
与removeMessages不同的是,object匹配的是内容,而不是对象引用。
void removeMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.callback == r
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
移除所有与给定 Handler (h)、Runnable 回调 ® 和对象 (object) 相匹配的消息
void removeEqualMessages(Handler h, Runnable r, Object object) {
if (h == null || r == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.callback == r
&& (object == null || object.equals(p.obj))) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.callback == r
&& (object == null || object.equals(n.obj))) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
与removeMessages(Handler h, Runnable r, Object object)不同的是object的比较的是内容,而不是对象引用。
void removeCallbacksAndMessages(Handler h, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
removeCallbacksAndMessages 方法旨在从消息队列中移除所有与给定 Handler (h) 和对象 (object) 相匹配的消息。object == null,就是移除与给定 Handler (h)相匹配的所有消息。
void removeCallbacksAndEqualMessages(Handler h, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h
&& (object == null || object.equals(p.obj))) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && (object == null || object.equals(n.obj))) {
Message nn = n.next;
n.recycleUnchecked();
p.next = nn;
continue;
}
}
p = n;
}
}
}
与removeCallbacksAndMessages不同的是,object不等于null时,object匹配的是内容,而不是对象引用。
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
回收消息队列中的所有消息
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);
}
}
}
移除消息队列中所有时间戳在未来(即 when 属性大于当前时间)的消息。
void dump(Printer pw, String prefix, Handler h) {
synchronized (this) {
long now = SystemClock.uptimeMillis();
int n = 0;
for (Message msg = mMessages; msg != null; msg = msg.next) {
if (h == null || h == msg.target) {
pw.println(prefix + "Message " + n + ": " + msg.toString(now));
}
n++;
}
pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
+ ", quitting=" + mQuitting + ")");
}
}
用于打印消息队列中的所有消息,以及队列的一些状态信息,如总消息数、是否正在轮询以及是否正在退出
void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long messageQueueToken = proto.start(fieldId);
synchronized (this) {
for (Message msg = mMessages; msg != null; msg = msg.next) {
msg.dumpDebug(proto, MessageQueueProto.MESSAGES);
}
proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
}
proto.end(messageQueueToken);
}
dumpDebug 方法使用 ProtoOutputStream 对象来序列化消息队列的状态到一个协议缓冲区(Protocol Buffers)流中。
因篇幅问题不能全部显示,请点此查看更多更全内容