一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情。
4.Message
a.类型
根据前面的分析,消息有三种类型:普通消息、异步消息及消息屏障;
普通消息:常用的通过Message.obtain()来获取的消息,target不能为null;
异步消息:和普通消息一样,target不能为null,且通过setAsynchronous(true)设置,有了这个标志位,消息机制会对它有些特别的处理;
消息屏障:也是一种消息,但是它的target为 null。只能通过MessageQueue中的postSyncBarrier方法发送一个消息屏障(该方法为私有,需要反射调用);
通过前面的分析可以看到,消息屏障和异步消息的作用很明显,在设置消息屏障后,异步消息具有优先处理的权利。比如:ViewRootImpl中UI绘制前会先发送消息屏障,再发送异步消息来绘制UI。
b.obtain()
在创建新的消息时,不会去通过new Message来创建,而是通过obtain(),先看一下:
//创建Message,通过Message.obtain(xx,xx,...)最终会调用到该方法
//当sPool不为空时,会从sPool里面取出message,不会频繁去new 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时,说明已经有执行过的message,此时取出链表头的msg1,然后把sPool指向sPool.next,假如sPool就存储了一个message,则如果在msg1未执行前,有新的message请求,需要执行new message();
c.recycleUnchecked()
//释放message,没有delete,只是将内容置空,然后把该消息放在sPool的head,供后续创建新的message使用
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++;
}
}
}
在message处理完后,会调用recycleUnchecked()来将Message内容置空,然后判断当sPoolSize小于50时,将刚执行完的msg的next指向sPool,sPool指向该msg,即把该msg作为表头,然后size++;当sPoolSize大于50时,就不会再插入了;
通过以上分析,执行完的message以链表形式存储,获取message时,会取出sPool表头的msg,然后sPool指向next、size--;该种创建及获取消息方式的好处:内存复用,防止内存抖动(不断的创建,释放),用到了享元设计模式。