面试handler系列: 上一篇:面试 - handle使用及原理(1)
Message的创建方式
面试的时候如果问你
Message
有几种创建方式 ?
Message msg = New Message()
: 这种方式就不用怎么多说 直接就是创建了一个Message
对象出来myHander.obtainMessage();
:myHandler
是Handler
类型的
直接使用该方法就可以创建一个Message
,看一下这源码
public final Message obtainMessage()
{
return Message.obtain(this);
}
里面调用了我们要提到了第三个创建Message
的方法
Message.obtain()
:
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
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();
}
上面的obtain()
源码中,使用了一个链表结构存储Message
作为一个缓存池,这样子可以避免重复创建多个实现对象。
第二种创建方法,只是先调用第三种从缓存池中获取到
Message
的对象再将Handler
赋值入给Message.target
。 以上三种都是创建Message
的方法
Message缓存池相关
Message
的数据结构中
public final class Message implements Parcelable {
......
/*package*/ Message next;
}
这个很明显是一个链表的结构,我们来看一下
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
这条Message
的单链表不为null
,取出链表头的Message
,重置一下sPool
, sPoolSize
(记录链表的长度)减一
如果sPool
为null
则返回一个新的Message
对象
看一下添加Message
到sPool
的这个方法
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
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++;
}
}
}
解释一下上面的源码: 清除一些变量信息,然后判断一下链表没有没超过最大值,没有就添加到链头并将链表大小加一
private static final int MAX_POOL_SIZE = 50;
链表的最大值为50
这个
Message
的细节就差不多看完了,主要是理解一下这种缓存池设计的一个思想吧,对于频繁创建的对象,我们最好是可以增加一个缓存池,需要对象的时候直接在里面获取到之前已经创建过的对象。而不是每次都是直接去创建。