android消息机制—MessageQueue

这篇文章只分析MessageQueue的enqueueMessage()、next()方法以及消息清除方法。

作用

  • 用于将消息插入和读取
  • 通过一个单链表的数据结构,维护消息列表

enqueueMessage()方法

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

boolean enqueueMessage(Message msg, long when) {
        // msg 必须有target也就是必须有handler
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
            ...
        synchronized (this) {
            ...
            msg.markInUse();
            //when 表示这个消息执行的时间,队列是按照消息执行时间排序的
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // 如果p为null则表示当前消息队列没有消息
                msg.next = p;
                //初始化头消息(改变了总是指向新的消息)
                mMessages = msg;
                //true代表有无消息,阻塞线程,false代表有消息,没有阻塞线程
                needWake = mBlocked;
            } else {
                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;
            }
            //是否唤醒Looper等待的线程
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

Next()方法

Message next() {
...
    //nextPollTimeoutMillis 表示nativePollOnce方法需要等待的时间
    //nextPollTimeoutMillis=-1表示一直阻塞切不会超时
    //nextPollTimeoutMillis>0 表示阻塞时长,可以理解为延迟多长时间发送消息
    int nextPollTimeoutMillis = 0;//表示不会阻塞,立即执行
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        //native的方法,在没有消息的时候回阻塞管道读取端,只有nativePollOnce返回之后才能往下执行
        nativePollOnce(ptr, nextPollTimeoutMillis);
        synchronized (this) {
            //从开机到现在的毫秒数
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // 找不是异步而且msg.target不为空的message
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                //开机到现在的毫秒数如果小于msg.when则代表还未到发送消息的时间
                if (now < msg.when) {
                   // 虽然有消息,但是还没有到运行的时候
                    //计算还有等待多久,并赋值给nextPollTimeoutMillis
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    //代表当前没有阻塞
                    mBlocked = false;
                   // 获取msg并且删除该节点 
                    if (prevMsg != null) 
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    msg.markInUse();
                    //返回拿到的消息
                    return msg;
                }
            } else {
                //没有消息,nextPollTimeoutMillis复位
                nextPollTimeoutMillis = -1;
            }
            .....
            .....
}

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

其他方法

消息退出quit()方法

清楚消息,这个函数会在Looper中分别被quit()和quitSafely()方法调用

void quit(boolean safe) {
  ...
    synchronized (this) {
        if (mQuitting) {
            return;
        }
        mQuitting = true;

        if (safe) {
            //移除延迟消息 Looper.quitSafely()调用
            removeAllFutureMessagesLocked();
        } else {
            //移除全部消息 Looper.quit()调用
            removeAllMessagesLocked();
        }
        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);
        }
    }
}

参考

深入理解 MessageQueue

Android 消息处理机制(Looper、Handler、MessageQueue,Message)

Android Handler机制6之MessageQueue简介

你可能感兴趣的:(android消息机制—MessageQueue)