Handler(六)--Message

系列目录: 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)