Handler---4部曲---3. MessageQueue队

作者: liys_android | 来源:发表于2021-11-07 00:04 被阅读0次

    Handler---4部曲---1. 总体流程
    Handler---4部曲---2. ThreadLocal 存储主流程
    Handler---4部曲---3. MessageQueue队列
    Handler---4部曲---4.细节补充

    本章内容

    MessageQueue队列.png

    一. 数据结构

    MessageQueue数据结构.png

    MessageQueue 3个成员变量

      ArrayList<IdleHandler> mIdleHandlers   --->
      boolean mBlocked;  --->next()是否阻塞 标记
      Message mMessages;  --->队列头
    

    Message 3个成员变量

       Handler target; //当前handler
       long when;  //消息延迟时间
       Message next;//下一个消息
    

    二. 消息分类

    2.1 同步消息
    2.2 异步消息
    2.3 同步屏障消息 --->撤销屏障removeSyncBarrier()
    2.4 空闲消息

    三. 4种消息的添加方式

    MessageQueue消息添加方式.png

    3.1 同步消息
    enqueueMessage(Message msg, long when) 添加

    boolean enqueueMessage(Message msg, long when) {
            //用此方法添加到队列, msg一定要给target赋值
            if (msg.target == null) {
                throw new IllegalArgumentException("Message must have a target.");
            }
    
            synchronized (this) {
                msg.when = when;
                Message p = mMessages;
                //如果 首次进来 || 时间=0 || 当前时间<队列头的时间
               //就把当前消息加到队列头
                if (p == null || when == 0 || when < p.when) { //
                    msg.next = p;
                    mMessages = msg;
                } else {
                    //把当前msg按照when 从小到大插入队列中
                    Message prev;
                    for (;;) {
                        prev = p; //
                        p = p.next;
                        if (p == null || when < p.when) { 
                            break;
                        }
                    }
                    //此时  prev.when<msg.when<p.when
                    msg.next = p; // invariant: p == prev.next
                    prev.next = msg;
                }
            }
            return true;
        }
    

    总结:把msg消息按时间顺序, 从小到大添加到队列中.

    3.2 异步消息
    和同步消息差不多, 只是把msg标记为异步.

     msg.setAsynchronous(true)  
     MessageQueue.enqueueMessage(msg, 时间xxx)
    

    3.3 同步屏障消息

    //添加同步屏障消息 
    int token = MessageQueue.postSyncBarrier();
    //移除同步屏障消息
    removeSyncBarrier(token);
    
        public int postSyncBarrier() {
            return postSyncBarrier(SystemClock.uptimeMillis());
        }
    
        private int postSyncBarrier(long when) {
            synchronized (this) {
                //获取Message 对象
                final Message msg = Message.obtain(); 
                msg.when = when; //时间赋值---当前时间
                // 以下的操作,和普通消息一样,按时间顺序 小到大排列
               // 最后msg就是队列头.
                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;
            }
        }
    

    总结:

    msg内部创建,也是按时间顺序进行排列的,
    msg.target = null
    msg.when = 当前时间
    

    3.4 空闲消息
    将消息添加到mIdleHandlers集合中

        public void addIdleHandler(@NonNull IdleHandler handler) {
            if (handler == null) {
                throw new NullPointerException("Can't add a null IdleHandler");
            }
            synchronized (this) {
                mIdleHandlers.add(handler);
            }
        }
    

    四. next()消息处理

    MessageQueue next出队流程.png
        Message next() {
            //mIdleHandlers集合数量
            int pendingIdleHandlerCount = -1;
            //阻塞休眠时间
            int nextPollTimeoutMillis = 0;
            for (;;) {
                //阻塞队列   nextPollTimeoutMillis休眠时间
                // -1 一直休眠, 等待唤醒
                // 0  不休眠, 马上执行
                // 大于0,休眠时间
                nativePollOnce(ptr, nextPollTimeoutMillis);
    
                synchronized (this) {
                    final long now = SystemClock.uptimeMillis();
                    Message prevMsg = null;
                    Message msg = mMessages; 
                    //判断是否有异步消息,  如果有,循环队列, 取出异步消息
                    if (msg != null && msg.target == null) {
                        do {
                            prevMsg = msg;
                            msg = msg.next;
                        } while (msg != null && !msg.isAsynchronous());
                    }
                   //注意:如果异步消息 的时间  > 当前时间, 则会一直等待, 其它消息得不到执行, 直到异步消息执行完为止.
                    
                    //此时msg代表取出的消息
                    if (msg != null) { //有消息
                        if (now < msg.when) { //没有到执行时间
                            //休眠时间 = (时间差,Integer.MAX_VALUE)中的小值.
                            nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                        } else {
                            // 马上执行消息
                            mBlocked = false; //标记线程不阻塞
                            if (prevMsg != null) { //异步消息时
                                prevMsg.next = msg.next;
                            } else { //同步消息时,队列头=下一个msg
                                mMessages = msg.next;
                            }
                            msg.next = null;
                            return msg;
                        }
                    } else {
                        // 如果没有消息,休眠时间--->一直休眠
                        nextPollTimeoutMillis = -1;
                    }
    
                    //是否退出(下一篇会讲)
                    if (mQuitting) {
                        dispose();
                        return null;
                    }
    
    
    //>>>>>>>>>>>>>>>下面是处理 空闲消息 mIdleHandlers>>>>>>>>>>>>>>>>>>>>>>>>>>
                    if (pendingIdleHandlerCount < 0  //首次进入
                            //&& (没有消息 || 当前时间 < 队列头时间)
                            && (mMessages == null || now < mMessages.when)) {
                        pendingIdleHandlerCount = mIdleHandlers.size();
                    }
                    //没有空闲消息处理
                    if (pendingIdleHandlerCount <= 0) {
                        mBlocked = true;  //标记,线程阻塞
                        continue;
                    }
                   //空闲消息List 转 数组
                    if (mPendingIdleHandlers == null) {
                        mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                    }
                    mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
               }
                
                //循环处理空闲消息
                for (int i = 0; i < pendingIdleHandlerCount; i++) {
                    final IdleHandler idler = mPendingIdleHandlers[i];
                    mPendingIdleHandlers[i] = null; // 释放数组内存
    
                    boolean keep = false;
                    try {
                        // //返回false才会删除任务, 否则重复执行
                        keep = idler.queueIdle();
                    } catch (Throwable t) {
                        Log.wtf(TAG, "IdleHandler threw exception", t);
                    }
    
                    if (!keep) {
                        synchronized (this) {
                            mIdleHandlers.remove(idler);
                        }
                    }
                }
    
                //重置变量
                pendingIdleHandlerCount = 0;
                nextPollTimeoutMillis = 0;
            }
        }
    
    Message消息处理:
    1. 首先获取队列头:Message msg = mMessages;
    2. 判断是否有同步屏障的消息. 如果有,会循环队列, 去找异步消息msg
      ①. 如果有异步消息,msg = 异步消息
      ②. 如果没有异步消息,msg==null.
    3. 如果msg==null, 线程进入休眠,nextPollTimeoutMillis = -1;
    4. 如果 msg!=null;
      ①. 当前时间 < msg.when, nextPollTimeoutMillis(休眠时间) = msg.when-当前时间
      ②. 当前时间 >= msg.when,取出msg给loop去处理
      ------>同步消息时,队列头=下一个msg, mMessages = msg.next
    空闲消息处理:

    没有msg消息处理的时候,才会处理空闲消息

    1. mIdleHandlers集合 转 数组
    2. 遍历数组 处理任务
    3. 任务返回false时, 才会从mIdleHandlers集合移除任务.
    4. 重置变量
    endingIdleHandlerCount = 0; 
    nextPollTimeoutMillis = 0;
    

    相关文章

      网友评论

        本文标题:Handler---4部曲---3. MessageQueue队

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