Android MessageQueue 源码分析

类注释

/**
 * 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

成员变量

mQuitAllowed
    // True if the message queue can be quit.
    @UnsupportedAppUsage
    private final boolean mQuitAllowed;

是否允许message queue退出。

mPtr
    @UnsupportedAppUsage
    @SuppressWarnings("unused")
    private long mPtr; // used by native code

native MessageQueue的指针变量

mMessages
    @UnsupportedAppUsage
    Message mMessages;

Message Queue消息队列的队首指针,即消息队列最前面的元素。

mIdleHandlers
    @UnsupportedAppUsage
    private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();

IdleHandler列表,用来记录需要进行callback回调的IdleHandler对象

mFileDescriptorRecords
    private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;

mFileDescriptorRecords为存储文件描述符的map数据结构

mPendingIdleHandlers
    private IdleHandler[] mPendingIdleHandlers;

处于等待的IdleHandler类型的数组

mQuitting
    private boolean mQuitting;

消息队列正在退出

mBlocked
    // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
    private boolean mBlocked;

指出是否next()被阻塞在了一个携带着非0超时参数的pollOnce() 上。

mNextBarrierToken
    // 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)

nativeInit
    private native static long nativeInit();

用于初始化native层的message queue.

nativeDestroy
    private native static void nativeDestroy(long ptr);

用于销毁native层的message queue

nativePollOnce
    @UnsupportedAppUsage
    private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/

等待timeoutMillis获取下一个消息

nativeWake
    private native static void nativeWake(long ptr);

native部分,我们再讲

nativeIsPolling
    private native static boolean nativeIsPolling(long ptr);

native部分,我们再讲

nativeSetFileDescriptorEvents
    private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

native部分,我们再讲

MessageQueue 构造函数
    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }
  1. MessageQueue创建的时候,会设置mQuitAllowed的值,告知是否允许退出。
  2. 创建native层的MessageQueue
finalize
    @Override
    protected void finalize() throws Throwable {
        try {
            dispose();
        } finally {
            super.finalize();
        }
    }

finalize() 方法是一个在对象被垃圾回收器回收之前调用的方法。

dispose
    // 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。

isIdle
    /**
     * 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,表示循环器当前是空闲的。

addIdleHandler
    /**
     * 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 不再需要被调用,因此会从集合中移除。

removeIdleHandler
    /**
     * 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.

isPolling
    /**
     * 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)以寻找更多的工作要做。这个方法是一个有用的信号,表明循环器仍在活跃状态,而不是在处理某个回调时被卡住.

isPollingLocked
    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。

addOnFileDescriptorEventListener
    /**
     * 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为当发生文件描述符事件时要调用的监听器。

removeOnFileDescriptorEventListener
    /**
     * 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 用于移除与指定文件描述符相关联的监听器。如果没有为该文件描述符注册任何监听器,那么这个方法不会进行任何操作。

updateOnFileDescriptorEventListenerLocked
    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);
        }
    }
  1. 获取文件描述符的整数表示.
  2. 如果 mFileDescriptorRecords 不为 null,则尝试查找该文件描述符的记录。如果找到记录并且事件掩码没有变化,则直接返回。
  3. 如果 events 不为零,则更新或创建新的记录,并调用 nativeSetFileDescriptorEvents 方法更新文件描述符的事件监听器。EVENT_ERROR 事件总是被监听,以确保能够捕获所有错误。
  4. 如果 events 为零且存在记录,则移除记录,并调用 nativeSetFileDescriptorEvents 方法取消事件监听。
dispatchEvents
    // 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;
    }
  1. dispatchEvents会被native代码调用,目的是将事件分发给注册的监听器,并根据监听器的响应来更新监听的事件集合。
  2. 查找文件描述符对应的FileDescriptorRecord,如果找不到,方法直接return。
  3. 通过events &= oldWatchedEvents;语句,将传入的事件events与当前监听的事件集oldWatchedEvents进行按位与操作。这一步的目的是过滤掉当前不想监听的事件,只保留那些实际想被监听的事件。
  4. 如果过滤后的事件不为空(即存在至少一个想被监听的事件),则调用监听器的onFileDescriptorEvents方法,传入文件描述符和触发的事件。该方法返回一个整数,表示监听器希望继续监听的新事件集(如果监听器返回0,可能表示不再需要监听任何事件)。
  5. 如果监听器希望继续监听新的事件集,并且这个新的事件集不为空,那么会在这个新的事件集中添加EVENT_ERROR事件(表示监听器希望监听错误事件)
  6. 如果监听器改变了它想要监听的事件集(即新的事件集与旧的事件集不同),并且在这段时间内监听器本身没有被更新(通过检查seq来确认),那么更新FileDescriptorRecord中的事件集。如果新的事件集为空,则从mFileDescriptorRecords中移除该记录,表示不再监听该文件描述符的任何事件。
next
    @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
        }
    }

获取并返回队列中的下一个消息,如果队列为空或者当前没有准备好的消息,则会等待直到有消息到来。

  1. mPtr指向native层的message queue。mPtr为空,表示native层的message queue已经被销毁,这个时候next方法直接返回,不再获取新的message事件。
  2. 定义了两个变量pendingIdleHandlerCount和nextPollTimeoutMillis。pendingIdleHandlerCount在第一次迭代时初始化为-1(表示尚未处理空闲处理器),而nextPollTimeoutMillis用于控制下一次轮询的超时时间,初始化为0。
  3. 通过一个无限循环来不断检查和处理消息。如果nextPollTimeoutMillis不为0(即不是第一次迭代),则调用Binder.flushPendingCommands()来确保所有的Binder命令都被处理。
  4. 调用nativePollOnce(ptr, nextPollTimeoutMillis)来轮询消息。这个方法是native方法,用于从消息队列中检索消息。
  5. 在同步块中,方法尝试从消息队列mMessages中检索下一个消息。如果队列的第一个消息被标记为障碍(target为null),则跳过所有同步消息,直到找到第一个异步消息或遍历完了消息队列中的所有消息。
  6. 如果找到的消息(msg)的预定时间when晚于当前时间now,则计算超时时间nextPollTimeoutMillis,以便在下一次轮询时唤醒.
  7. 如果找到的消息的预定时间已到,则从队列中移除该消息,并将其next指针置为null,表示它已被从队列中取出。然后,调用msg.markInUse()标记消息正在使用中,并返回该消息。
  8. 如果消息队列为空或者没有找到异常消息,都会置nextPollTimeoutMillis = -1。
  9. 如果消息队列为空或者没有找到异步消息或者消息队列头的同步消息或者找到的异步消息还没有到需要处理的时间,会判断mQuitting的值。如果mQuitting为true,表示Looper正在停止消息循环,则调用dispose()方法释放资源。
  10. 如果是第一次检查空闲处理器,以及消息队列为空或者消息队列头的同步消息或者异步消息还没有到需要处理的时间,初始化初始化空闲处理器计数。
  11. 如果pendingIdleHandlerCount小于等于0,表示没有需要处理的IdleHandler,continue继续执行下次轮询。
  12. 如果pendingIdleHandlerCount大于0,将mIdleHandlers转化为数组进行处理。
  13. 回调每一个IdleHandler的queueIdle方法,且只有在for循环第一次迭代的时候才会执行。
  14. 如果queueIdle方法返回的是false,意味着以后不再需要进行回调,则把它从mIdleHandlers列表中移除。
  15. 重置pendingIdleHandlerCount的值为0,是为了确保在下一轮Looper循环中,已经执行过的空闲处理器不会被重复执行,以后都不会执行了?TODO
  16. 重置nextPollTimeoutMillis的值为0,意味着Looper将不会在下一次迭代中等待任何超时时间,而是会立即检查消息队列中是否有新的消息。这是因为在执行空闲处理器的过程中,新的消息可能已经被添加到消息队列中,因此Looper需要立即检查这些新消息,而不是等待一个可能不必要的超时时间。
  17. next方法的主要作用是获取并返回队列中的下一个消息,如果队列为空或者当前没有准备好的消息,则会等待直到有消息到来。当获取到队列中的一个满足条件的消息的时候,直接返回,否则,则进行下次循环。下次循环的执行受到nextPollTimeoutMillis值的影响,具体的指的是根据nextPollTimeoutMillis值的不同,nativePollOnce的执行时间会有不同,有可能立马就返回,有可能block在这里,以后再分析nativePollOnce。
  18. 只有next方法通过for循环,获取到满足条件可以执行的消息(同步或者异步)才算是mBlocked == false,否则,即当消息队列为空,找不到异步方法,找到的异步或者同步方法还没有到约定的执行时间,并且没有要执行的idlehandler的时候,mBlocked = true。
quit
    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
        }
    }
  1. 首先检查一个成员变量mQuitAllowed。如果该变量为false,则抛出IllegalStateException异常,表明当前线程(主线程)不被允许退出。
  2. 首先检查mQuitting成员变量是否已经被设置为true。如果是,那么意味着退出过程已经开始或已经完成,因此方法可以直接返回。
  3. 如果safe为true,则调用removeAllFutureMessagesLocked()方法移除所有未来的消息。这可能意味着只移除那些尚未到达执行时间的消息,允许当前正在执行或已经排队但即将执行的消息继续执行。
    如果safe为false,则调用removeAllMessagesLocked()方法移除所有消息,无论它们是否即将执行。这可能会导致当前正在执行的消息被中断。
  4. 唤醒与这个退出过程相关的任何等待或阻塞的线程或组件。
postSyncBarrier
    /**
     * 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),暂停所有后续同步消息的执行,直到该屏障被移除。

  1. 在消息队列遇到这个屏障之前,消息处理会正常进行。一旦遇到屏障,所有后续的同步消息(即非异步消息)将被阻塞(阻止执行),直到该屏障通过调用removeSyncBarrier方法并指定发布屏障时返回的令牌(token)来释放
  2. 异步消息(通过Message#isAsynchronous方法标识)不受此屏障影响,将继续按正常方式处理。
  3. 为了确保消息队列能够恢复正常操作,对postSyncBarrier的每次调用都必须通过removeSyncBarrier方法的对应调用来匹配,传入相同的令牌作为参数。如果不这样做,应用程序可能会挂起或陷入无响应状态。
  4. postSyncBarrier的作用是将一个参数arg1为token的Message放到时间顺序放到队列中
removeSyncBarrier
    /**
     * 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);
            }
        }
    }
  1. 用于移除一个同步屏障(synchronization barrier).通过遍历mMessages链表来查找具有指定token的同步屏障。同步屏障消息的特点是它们的target字段为null,且arg1字段存储了屏障的token.
  2. 判断移除屏障后是否需要唤醒消息队列。如果移除的不是队列中的第一个消息,则不需要唤醒。如果移除的是队列中的第一个消息(即prev为null),队列为空或者队列不为空且下一个消息的目标(target)不为null(即不是另一个同步屏障),则需要唤醒队列。
enqueueMessage
    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;
    }
  1. 用于将一个Message对象加入到消息队列中,并指定其被处理的时间(when)。这个方法的目的是在消息队列中以合适的位置插入这个消息,并在需要时唤醒等待的线程以处理消息
  2. 参数检查:
    首先检查msg(即Message对象)的target(即消息的接收者)是否为null。如果是,则抛出IllegalArgumentException异常,因为消息必须有一个目标接收者。
    然后检查该消息是否已经在使用中(通过isInUse()方法)。如果是,则抛出IllegalStateException异常,因为消息不能同时被多个地方使用
  3. 线程状态检查:
    接着检查mQuitting标志,这个标志通常用于指示当前线程是否正在退出。如果mQuitting为true,则记录一条警告日志,并回收该消息(通过msg.recycle()),然后返回false表示消息未入队。
  4. 标记消息为使用中并设置处理时间:
    调用msg.markInUse()将消息标记为正在使用中。
    设置消息的when属性,即消息应该在何时被处理(相对于某个时间基准,比如当前时间)
  5. 插入消息到队列:
    首先,检查消息队列(mMessages)是否为空,或者新消息的when时间是否小于队列头消息的when时间。如果是,说明新消息应该成为队列的新头,并可能需要唤醒等待的线程。
    如果新消息不应该成为队列的新头,则在队列中找到合适的插入位置,即找到第一个when时间大于或等于新消息when时间的消息,并将新消息插入到这个位置之前。
    在这个过程中,还会检查是否需要唤醒等待的线程。这通常发生在队列头有屏障消息(target为null)且新消息是异步消息时。在needWake为true的情况下,如果插入位置的前面,依然有异步消息,那就置needWake为false,不唤醒等待的线程。
  6. 如果需要唤醒等待的线程(即needWake为true),则调用nativeWake(mPtr)方法(这是一个本地方法调用,具体实现在Android的底层C/C++代码中),通过传递的mPtr(通常是一个指向本地消息队列的指针)来唤醒等待的线程。
hasMessages
    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,则不对消息中的对象进行匹配检查。

hasEqualMessages
    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 方法则用于比较两个对象的内容是否相等。

hasMessages
    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 是否在其消息队列中有待处理的消息,而不关心这些消息的具体内容或类型

removeMessages
    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 相匹配的消息

removeEqualMessages
    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匹配的是内容,而不是对象引用。

removeMessages
    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) 相匹配的消息

removeEqualMessages
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的比较的是内容,而不是对象引用。

removeCallbacksAndMessages
    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)相匹配的所有消息。

removeCallbacksAndEqualMessages
    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匹配的是内容,而不是对象引用。

removeAllMessagesLocked
    private void removeAllMessagesLocked() {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            p.recycleUnchecked();
            p = n;
        }
        mMessages = null;
    }

回收消息队列中的所有消息

removeAllFutureMessagesLocked
    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 属性大于当前时间)的消息。

dump
    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 + ")");
        }
    }

用于打印消息队列中的所有消息,以及队列的一些状态信息,如总消息数、是否正在轮询以及是否正在退出

dumpDebug
    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)流中。

  • 21
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值