Android-MessageQueue

一、MessageQueue简介

  • MessageQueue即消息队列,这个消息队列和Message消息对象对象池里面的消息对象池(单链表)可不是同一个东西。
  • MessageQueue是一个消息队列,Handler将Message发送到消息队列中,消息队列会按照一定的规则取出要执行的Message。
  • 需要注意的是Java层的MessageQueue负责处理Java的消息,native也有一个MessageQueue负责处理native的消息。
  • 这里有必要提一下MessageQueue的数据结构,是一个单向链表,Message对象有个next字段保存列表中的下一个,MessageQueue中的mMessages保存链表的第一个元素。
  • 用于将消息插入和读取
  • 通过一个单链表的数据结构,维护消息列表

二、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.
 *
 * 

You can retrieve the MessageQueue for the current thread with * {@link Looper#myQueue() Looper.myQueue()}. */ public final class MessageQueue { .... }

它是一个被Looper分发、低等级的持有Message集合的类。Message并不是直接加到MessageQueue的,而是通过Handler对象和Looper关联到一起。
我们可以通过Looper.myQueue()方法来检索当前线程的MessageQueue
它是一个低等级的持有Messages集合的类,被Looper分发。Messages并不是直接加到MessageQueue的,而是通过Handler对象和Looper关联到一起。我们可以通过Looper.myQueue()方法来检索当前线程的。

三、MessageQueue成员变量

    // True if the message queue can be quit.
    //用于标示消息队列是否可以被关闭,主线程的消息队列不可关闭
    private final boolean mQuitAllowed;

    @SuppressWarnings("unused")
    // 该变量用于保存native代码中的MessageQueue的指针
    private long mPtr; // used by native code

    //在MessageQueue中,所有的Message是以链表的形式组织在一起的,该变量保存了链表的第一个元素,也可以说它就是链表的本身
    Message mMessages;

    //当Handler线程处于空闲状态的时候(MessageQueue没有其他Message时),可以利用它来处理一些事物,该变量就是用于保存这些空闲时候要处理的事务
    private final ArrayList mIdleHandlers = new ArrayList();

    // 注册FileDescriptor以及感兴趣的Events,例如文件输入、输出和错误,设置回调函数,最后
    // 调用nativeSetFileDescriptorEvent注册到C++层中,
    // 当产生相应事件时,由C++层调用Java的DispathEvents,激活相应的回调函数
    private SparseArray mFileDescriptorRecords;

     // 用于保存将要被执行的IdleHandler
    private IdleHandler[] mPendingIdleHandlers;

    //标示MessageQueue是否正在关闭。
    private boolean mQuitting;

    // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
    // 标示 MessageQueue是否阻塞
    private boolean mBlocked;

    // The next barrier token.
    // Barriers are indicated by messages with a null target whose arg1 field carries the token.
    // 在MessageQueue里面有一个概念叫做障栅,它用于拦截同步的Message,阻止这些消息被执行,
    // 只有异步Message才会放行。障栅本身也是一个Message,只是它的target为null并且arg1用于区分不同的障栅,
     // 所以该变量就是用于不断累加生成不同的障栅。
    private int mNextBarrierToken;

四、MessageQueue的构造函数

 MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

MessageQueue只是有一个构造函数,该构造函数是包内可见的,其内部就两行代码,分别是设置了MessageQueue是否可以退出和native层代码的相关初始化。

调用的地方Looper#Looper(boolean quitAllowed)
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed); // 消息队列
        mThread = Thread.currentThread();       // 当前线程
    }

在Looper中创建了MessageQueue。


MessageQueue处理消息

消息入队 enqueueMessage()

这个方法主要是用来处理发送消息的,当Handler通过自己enqueueMessage()将消息发送到这该函数中。该函数首先会判断判断是否msg.target有Handler的引用,消息会被按着时间顺序被添加到队列中。

Handler#enqueueMessage()

    /**
     * 将Msg添加到消息队列中
     *
     * @param queue 这个就是消息队列 从Looper里面获取到的
     * @param msg    发送的具体消息
     * @param uptimeMillis 处理时间
     * @return
     */
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) {
        // Handler 保存进来了 looper的时候使用这个Handler 处理消息的
        // 为什么使用匿名内部类来创建Handler的方法会有内存泄漏的风险?
        msg.target = this;
        // 线程数据
        msg.workSourceUid = ThreadLocalWorkSource.getUid();
        // 异步
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        // 调用的是 Looper 的 Queen 的函数
        return queue.enqueueMessage(msg, uptimeMillis);
    }

MessageQueue#enqueueMessage(Message msg, long when)


boolean enqueueMessage(Message msg, long when) {
        // msg 必须有target也就是必须有handler
        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) {
            // 标示MessageQueue是否正在关闭。
            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();
            //when 表示这个消息执行的时间,队列是按照消息执行时间排序的
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // 如果p为null则表示当前消息队列没有消息
                // New head, wake up the event queue if blocked.
                msg.next = p;
                // 初始化头消息(改变了总是指向新的消息)
                mMessages = msg;
                 // true代表无消息,阻塞线程,false代表有消息,没有阻塞线程
                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;
                // 将消息放到队列,消息是按照msg的when 排序
                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()

Looper.loop() 调用 Message msg = queue.next();

public static void loop() {
       
       ....

        // 进入loop的主循环方法
        for (; ; ) {
            Message msg = queue.next(); // might block 可能会阻塞,因为next()方法可能会无限循环

            ....

            // 回收
            msg.recycleUnchecked();
        }
}

next()

 @UnsupportedAppUsage
    Message next() {

        //nextPollTimeoutMillis 表示nativePollOnce方法需要等待的时间
        //nextPollTimeoutMillis=-1表示一直阻塞切不会超时
        //nextPollTimeoutMillis>0 表示阻塞时长,可以理解为延迟多长时间发送消息

        // 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();
            }

            //native的方法,在没有消息的时候会阻塞管道读取端,只有nativePollOnce返回之后才能往下执行
            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.target不为空的message
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    //开机到现在的毫秒数如果小于msg.when则代表还未到发送消息的时间
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        // 虽然有消息,但是还没有到运行的时候
                        //计算还有等待多久,并赋值给nextPollTimeoutMillis
                        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 {
                    //没有消息,nextPollTimeoutMillis复位
                    // 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;
        }
    }

上面的next()部分代码中有部分是native相关的知识,这里不做说明,我们只了解next执行的思路。next()方法中有一个无限循环,里面调用了阻塞方法,如果有消息或者等待延迟的时间到了才不会阻塞,系统将继续执行,在获取到消息后会将消息赋值给新的变量,并将这个消息从单链表中删除。

Looper.loop()里面的死循环不会死机是因为MessageQueue.next()里面调用了native层的函数阻塞了程序的循环。

移除消息 removeMessages()

就是将消息从链表移除,同时将移除的消息添加到消息池,提供循环复用。
采用了两个while循环,第一个循环是从队头开始,移除符合条件的消息,第二个循环是从头部移除完连续的满足条件的消息之后,再从队列后面继续查询是否有满足条件的消息需要被移除。


消息退出quit()方法

Looper调用 Looper.quit()

public void quit() {
        mQueue.quit(false);
}

public void quitSafely() {
        mQueue.quit(true);
}

MessageQueue.quite(boolean safe)

void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                //移除延迟消息 Looper.quitSafely()调用
                removeAllFutureMessagesLocked();
            } else {
                //移除全部消息 Looper.quit()调用
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }

removeAllMessagesLocked()

// 该方法是清楚消息列表的全部消息
private void removeAllMessagesLocked() {
    Message p = mMessages; // mMessages 为消息队列的表头的消息
    // 清除列表中的所有消息,recycleUnchecked()为进行回收
    while (p != null) { 
        Message n = p.next;
        p.recycleUnchecked();
     p = n;
    }
    // mMessages 为 null 时Looper 的 for 循环就会结束
    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 while中
            do {
                p = n;
                n = p.next;
                p.recycleUnchecked();
            } while (n != null);
        }
    }
}

同步消息屏障
     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;
        }
    }

你可能感兴趣的:(Android-MessageQueue)