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

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

本章内容

一. 数据结构

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种消息的添加方式

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()消息处理

    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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章