为什么Android建议Message.obtain(),而不是直接用new关键字
前言
一般情况下,用Handler发送一个消息,即Message对象,可以通过new关键字创建,也可以通过Message.obtain()创建,在Android源码中,Message的构造方法上边可以看到如下注释:
/** Constructor (but the preferred way to get a Message is to call {@link #obtain() Message.obtain()}).
*/
public Message() {
}
注释意思是:首选Message.obtain()来获取Message对象
为什么Android要推荐使用Message.obtain()方法来获取呢???让我们来看看源码里的奥妙,一起来fucking the source code
源码分析Message.obtain()方法
/**
-
Return a new Message instance from the global pool. Allows us to
-
avoid allocating new objects in many cases.
-
从一个pool里获取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();
}
可以看到,如何sPool对象为null,则new一个Message对象;如果不为空,就把sPool的第一个节点对象返回,然后把sPool指向下一个节点。那么sPool到底是什么呢???其实他就是一个Message链表,每个Message里都有一个next字段,类型也是Message对象。
到这里也看到了Message对象的获取方式分为两种情况
总结:
如果sPool为null,则直接通过new来获取
如果sPool不为null,则将sPool的第一个节点返回,然后把sPool指向其下一个节点
那么这里又有一个问题,sPool是什么时候生成和赋值的,什么时候向sPool池中添加Message对象的呢?接下来我们通过源码定位到了recycleUnchecked()这个方法,这个方法又是在recycle()方法中调用的
源码解析recycle()和recycleUnchecked()方法
public void recycle() {
//判断当前message是否可以被回收(是否正在被使用)
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
- “is still in use.”);
}
return;
}
//当前message对象可以被回收
recycleUnchecked();
}
void recycleUnchec
ked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
//这些就是清除当前message对象的成员变量信息(相当于一个新的message)
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
//当前池中的size小于最大size,就为池中添加当前message
//MAX_POOL_SIZE 大小默认为50
if (sPoolSize < MAX_POOL_SIZE) {
//当前message作为sPool的第一个节点
next = sPool;
//再将当前message赋值给sPool
sPool = this;
sPoolSize++;
}
}
}
这两个方法的源码还是比较容易看懂的,基本总结就是当message对象被回收的时候,先清除其成员变量信息,然后将该对象作为sPool池的第一个节点添加到池中。
那么问题又来了,message对象什么时候被回收呢???咱们可以猜想一下,当message对象不用了之后被回收;那么在Android的消息机制中,是通过Looper.loop()方法从消息队列中取出消息进行处理,那么咱们就去这个方法里去寻找我们想要的答案
这两个方法的源码还是比较容易看懂的,基本总结就是当message对象被回收的时候,先清除其成员变量信息,然后将该对象作为sPool池的第一个节点添加到池中。
那么问题又来了,message对象什么时候被回收呢???咱们可以猜想一下,当message对象不用了之后被回收;那么在Android的消息机制中,是通过Looper.loop()方法从消息队列中取出消息进行处理,那么咱们就去这个方法里去寻找我们想要的答案