美文网首页
Handler(六)--Message

Handler(六)--Message

作者: azu_test | 来源:发表于2019-02-18 14:11 被阅读0次

    系列目录: Handler机制原理

    Message使用介绍

    • 定义一个可以发送给Handler的描述和任意数据对象的消息。
    • 此对象包含两个额外的int字段和一个额外的对象字段,这样就可以使用在很多情况下不用做分配工作。
    • Message的构造器是公开的,但是获取Message对象的最好方法是调用Message.obtain()或者Handler.obtainMessage(),这样是从一个可回收的对象池中获取Message对象。

    成员变量

        // 回复跨进程的Messenger 
        public Messenger replyTo;
    
        // Messager发送这的Uid
        public int sendingUid = -1;
    
        // 正在使用的标志值 表示当前Message 正处于使用状态,当Message处于消息队列中、处于消息池中或者Handler正在处理Message的时候,它就处于使用状态。
        /*package*/ static final int FLAG_IN_USE = 1 << 0;
    
        // 异步标志值 表示当前Message是异步的。
        /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
    
        // 消息标志值 在调用copyFrom()方法时,该常量将会被设置,其值其实和FLAG_IN_USE一样
        /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
    
        // 消息标志,上面三个常量 FLAG 用在这里
        /*package*/ int flags;
    
        // 用于存储发送消息的时间点,以毫秒为单位
        /*package*/ long when;
    
        // 用于存储比较复杂的数据
        /*package*/ Bundle data;
        
        // 用于存储发送当前Message的Handler对象,前面提到过Handler其实和Message相互持有引用的
        /*package*/ Handler target;
        
        // 用于存储将会执行的Runnable对象,前面提到过除了handlerMessage(Message msg)方法,你也可以使用Runnable执行操作,要注意的是这种方法并不会创建新的线程。
        /*package*/ Runnable callback;
     
        // 指向下一个Message,也就是线程池其实是一个链表结构
        /*package*/ Message next;
    
        // 该静态变量仅仅是为了给同步块提供一个锁而已
        private static final Object sPoolSync = new Object();
    
        //该静态的Message是整个线程池链表的头部,通过它才能够逐个取出对象池的Message
        private static Message sPool;
    
        // 该静态变量用于记录对象池中的Message的数量,也就是链表的长度
        private static int sPoolSize = 0;
      
        // 设置了对象池中的Message的最大数量,也就是链表的最大长度
        private static final int MAX_POOL_SIZE = 50;
    
         //该版本系统是否支持回收标志位
        private static boolean gCheckRecycle = true;
    

    获取Message对象

    1. 构造方法
        public Message() {
        }
    
    2. Message.obtain()方法

    obtain()方法有很多种类型,此处只做简单的分析,剩下的应该类似

        public static Message obtain() {
           // 保证线程安全
            synchronized (sPoolSync) {
                if (sPool != null) {
                    Message m = sPool;
                    sPool = m.next;
                    m.next = null;
                     // flags为移除使用标志
                    m.flags = 0; // clear in-use flag
                    sPoolSize--;
                    return m;
                }
            }
            return new Message();
        }
    

    从全局的pool返回一个实例化的Message对象。这样可以避免我们重新创建冗余的对象。

    1. 判断sPool是否为空,如果消息对象池为空,则直接new Message并返回
    2. Message m = sPool,将消息对象池中的对象取出来,为m。
    3. sPool = m.next,将消息对象池中的下一个可以复用的Message对象(m.next)赋值为消息对象池中的当前对象。(如果消息对象池就之前就一个,则此时sPool=null)
    4. 将m.next置为null,因为之前已经把这个对象取出来了,所以无所谓了。
    5. m.flags = 0,设置m的标记位,标记位正在被使用
    6. sPoolSize--,因为已经把m取出了,这时候要把消息对象池的容量减一。
    3. Message.recycleUnchecked()方法
        void recycleUnchecked() {
            // 添加正在使用标志位,其他情况就除掉
            flags = FLAG_IN_USE;
            what = 0;
            arg1 = 0;
            arg2 = 0;
            obj = null;
            replyTo = null;
            sendingUid = -1;
            when = 0;
            target = null;
            callback = null;
            data = null;
            //拿到同步锁,以避免线程不安全
            synchronized (sPoolSync) {
                if (sPoolSize < MAX_POOL_SIZE) {
                    next = sPool;
                    sPool = this;
                    sPoolSize++;
                }
            }
        }
    

    Message从MessageQueue中取出使用后,会调用此方法recycleUnchecked ()。代码不做详细解析,但是我们可以看出采用了一种 后入先出的链表管理模式。加了一个最大复用限制个数。

    其他带参obtain()的方法不再分析,主要是学习里面的复用方法思路。

    相关文章

      网友评论

          本文标题:Handler(六)--Message

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