美文网首页
android消息机制—MessageQueue

android消息机制—MessageQueue

作者: 韩明泽 | 来源:发表于2019-02-11 16:44 被阅读3次

    这篇文章只分析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

          本文链接:https://www.haomeiwen.com/subject/ioiqeqtx.html