系列目录: Handler机制原理
Message使用介绍
- 定义一个可以发送给Handler的描述和任意数据对象的消息。
- 此对象包含两个额外的int字段和一个额外的对象字段,这样就可以使用在很多情况下不用做分配工作。
- Message的构造器是公开的,但是获取Message对象的最好方法是调用Message.obtain()或者Handler.obtainMessage(),这样是从一个可回收的对象池中获取Message对象。
成员变量
// 回复跨进程的Messenger
public Messenger replyTo;
// Messager发送这的Uid
public int sendingUid = -1;
// 正在使用的标志值 表示当前Message 正处于使用状态,当Message处于消息队列中、处于消息池中或者Handler正在处理Message的时候,它就处于使用状态。
/*package*/ static final int FLAG_IN_USE = 1 << 0;
// 异步标志值 表示当前Message是异步的。
/*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
// 消息标志值 在调用copyFrom()方法时,该常量将会被设置,其值其实和FLAG_IN_USE一样
/*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
// 消息标志,上面三个常量 FLAG 用在这里
/*package*/ int flags;
// 用于存储发送消息的时间点,以毫秒为单位
/*package*/ long when;
// 用于存储比较复杂的数据
/*package*/ Bundle data;
// 用于存储发送当前Message的Handler对象,前面提到过Handler其实和Message相互持有引用的
/*package*/ Handler target;
// 用于存储将会执行的Runnable对象,前面提到过除了handlerMessage(Message msg)方法,你也可以使用Runnable执行操作,要注意的是这种方法并不会创建新的线程。
/*package*/ Runnable callback;
// 指向下一个Message,也就是线程池其实是一个链表结构
/*package*/ Message next;
// 该静态变量仅仅是为了给同步块提供一个锁而已
private static final Object sPoolSync = new Object();
//该静态的Message是整个线程池链表的头部,通过它才能够逐个取出对象池的Message
private static Message sPool;
// 该静态变量用于记录对象池中的Message的数量,也就是链表的长度
private static int sPoolSize = 0;
// 设置了对象池中的Message的最大数量,也就是链表的最大长度
private static final int MAX_POOL_SIZE = 50;
//该版本系统是否支持回收标志位
private static boolean gCheckRecycle = true;
获取Message对象
1. 构造方法
public Message() {
}
2. Message.obtain()方法
obtain()方法有很多种类型,此处只做简单的分析,剩下的应该类似
public static Message obtain() {
// 保证线程安全
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
// flags为移除使用标志
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
从全局的pool返回一个实例化的Message对象。这样可以避免我们重新创建冗余的对象。
- 判断sPool是否为空,如果消息对象池为空,则直接new Message并返回
- Message m = sPool,将消息对象池中的对象取出来,为m。
- sPool = m.next,将消息对象池中的下一个可以复用的Message对象(m.next)赋值为消息对象池中的当前对象。(如果消息对象池就之前就一个,则此时sPool=null)
- 将m.next置为null,因为之前已经把这个对象取出来了,所以无所谓了。
- m.flags = 0,设置m的标记位,标记位正在被使用
- sPoolSize--,因为已经把m取出了,这时候要把消息对象池的容量减一。
3. Message.recycleUnchecked()方法
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从MessageQueue中取出使用后,会调用此方法
recycleUnchecked ()
。代码不做详细解析,但是我们可以看出采用了一种后入先出
的链表管理模式。加了一个最大复用限制个数。
其他带参obtain()的方法不再分析,主要是学习里面的复用方法思路。
网友评论