Message源码分析

Message 在Android中主要是在 消息循环机制 中使用,即配合 Handler,LooperMessageQueue来进行线程切换,线程间传递数据。Message存储了我们所有需要的东西。

还可以配合Handler在IPC中传递数据。

我们在使用的过程中应该使用obtain()这个方法来重复利用消息池里面的Message

而复用池本质上就是一个单向链表,为了更好的理解,Message复用池的实现,我们先来看下,简单的单向链表实现.

public final class Message implements Parcelable {
    ...
    // 下一个节点的引用
    Message next;
    // 这里起到类锁的功能,相当于 Message.class
    private static final Object sPoolSync = new Object();
    // 可以类比为 头结点
    private static Message sPool;
    // 链表的长度
    private static int sPoolSize = 0;
    // 链表的最大长度
    private static final int MAX_POOL_SIZE = 50;
    // 获取Message对象,类比单向链表的removeHead操作
    public static Message obtain() {
        // 同步锁, 这里相当于锁住 Message.class, 起到类锁的作用, 每一个Message实例都是同一把锁
        synchronized (sPoolSync) {
            // 链表中有可复用的Message,直接拿到头结点,然后将头结点指向下一个元素
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        // 链表中,没有可复用的message,直接new
        return new Message();
    }
    // 类比单向链表的insertHead操作
    void recycleUnchecked() {
        // 清空数据操作
        obj = null;
        ...
        // 同步锁
        synchronized (sPoolSync) {
            // 如果链表长度小于50,将当前结点,加入链表头部
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
    ...
}

从上面的分析,我们来梳理一下整体的流程思想.

  • Message 使用一个静态变量,来起到头结点的作用.

静态变量属于类变量,内存中只会存在一份引用,正好能起到 头结点的作用

  • Message 将自身作为Node节点,存储下一个节点的引用,和自身数据
  • obtain()方法相当于链表中移除首元素,并返回该元素的操作

从复用池中获取Message避免了 new创建的消耗.

  • recycleUnchecked()方法相当于链表中将节点加入到头部的操作

添加到复用池之前,会先将Message中的数据清空.

  • Message添加了线程安全的操作
  • Message复用池最多保存50个使用完待复用的Message

50个可能是考虑到内存开销和时间开销的平衡, 不是将数据无限制的添加到复用池.


Message将自身作为节点, 使用一个静态变量作为头结点,让Message自身形成一个链表,而链表中存的是 已经清空数据的Message对象, 以这种方式起到复用的效果!


猜你喜欢

转载自www.cnblogs.com/lianzhen/p/12925206.html