相关推荐:
- Android 源码阅读 | Handler
- Android 源码阅读 | Looper
- Android 源码阅读 | MessageQueue
- Android 源码阅读 | Message
- Android 自定义 View | 扭曲动效
概述-类注释
/**
*
* 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 技术,不定时推送新鲜文章,如果你有好的文章想和大家分享,欢迎关注投稿!