Android 源码阅读 | Message

635 阅读1分钟

Android 源码阅读.png

相关推荐:

概述-类注释

/**
 * 
 * Defines a message containing a description and arbitrary data object that can be
 * sent to a {@link Handler}.  This object contains two extra int fields and an
 * extra object field that allow you to not do allocations in many cases.  
 *
 * <p class="note">While the constructor of Message is public, the best way to get
 * one of these is to call {@link #obtain Message.obtain()} or one of the
 * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
 * them from a pool of recycled objects.</p>
 */
  • Message是一个消息类,携带着描述和任意数据对象。Message包括两个额外的int字段和一个 extra object 字段。

  • 虽然Message的构造方法是一个公共方法,但是最好通过 Message.obtainMessage() 的方法去获得一个Message对象,因为此方法会从一个缓存Message的缓存池中重新利用被丢弃的Message而不需要重新初始化重新分配对象。

缓存机制

在类注释里面,我们看到,Message会维护一个Message的缓存对象池,通过 Message.obtainMessage() 去获取一个缓存对象。翻查相关的源码发现,在 Looper 里面,Message 被分发处理后,会调用 msg.recycleUnchecked()

public static void loop() {
   final Looper me = myLooper();
   //省略...
   for (;;) {
       Message msg = queue.next(); // might block
       //省略...
       // 1. msg.target,其实就是 handler 对象,调用分发方法
       try {
           msg.target.dispatchMessage(msg);
       } finally {
           if (traceTag != 0) {
               Trace.traceEnd(traceTag);
           }
       }
       //省略...
       // 2. 分发完成后,直接 recycle 回收 messageBean
       msg.recycleUnchecked();
   }
}

在Looper的 loop() 中,先进行 Message 的消息分发,分发完成后,直接 recycleUnchecked 回收:

Message next;
private static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;

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 的一些信息进行 reset,然后插入到缓存池中,缓存池以链式相连,有固定的大小为50.

通过 obtain() 方法可以从队列中取出重复利用的 message:

public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

总结

  • 缓存池其实是一个链表的形式维护
  • 每次使用都优先从链头开始取出使用,每次缓存message都是缓存到链头,先进后出的形式。
  • 缓存池的大小为50.

码字不易,方便的话素质三连,或者关注我的公众号 技术酱,专注 Android 技术,不定时推送新鲜文章,如果你有好的文章想和大家分享,欢迎关注投稿!

技术酱