Message翻译过来是消息,顾名思义,在Android中它定义了一个消息体,消息包含了描述和任意的数据对象,可以被发送给Handler。Message对象包含了两个int类型的额外字段,也包含一个object类型的额外字段,可以在多种情况下不分配。
尽管Message的构造器是public类型的,但最好的获取Message对象的方法是调用Message.obtain()方法或者Handler.obtainMessage()
享元模式是23种Gof设计模式结构化模式的一种,它在处理大量具有简单重复元素,单独存储会使用大量内存的时候非常有用,通常做法是把共享的数据存储在外部的数据结构里面,使用的时候把他们传递给对象。
Handler.obtainMessage方法内部也是调用的Message.obtain,所以只看后者:
public static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0; #当前消息池的大小
....
....
private static final int MAX_POOL_SIZE = 50; #缓存消息池最大容量
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如果是空,则new一个新的Message,非空的话从缓存池获取对象,并清空获取到的Message对象的flags,消息池当前大小减1。此外Message还有几个重载的obtain方法,分别对应不同场景对Message对象设置不同的属性,本质上都是从缓存池拿对象。
Message回收共有两个方法,回收就是把Message对象放在全局的回收池,两个方法分别是:
/**
* Recycles a Message that may be in-use.回收一个可能在使用的消息
* Used internally by the MessageQueue and Looper when disposing of queued Messages.处理完队列消息时在MessageQueue和Looper内部使用
*/
@UnsupportedAppUsage
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 = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
#缓存池对象小于50,当前缓存池后移,当前对象放在链表首部,缓存池大小加一
next = sPool;
sPool = this;
sPoolSize++;
}
}
}recycleUnchecked方法可能回收一个正在使用的message,in-use表示在缓存池内,或者在消息队列里,只有在obtain的时候消息的状态才不是in-use。这个方法在Looper.loop循环获取到消息并dispatch以后会使用:
public static void loop() {
final Looper me = myLooper();
.....
me.mInLoop = true;
final MessageQueue queue = me.mQueue;
....
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
....
try {
msg.target.dispatchMessage(msg);
...
} catch (Exception exception) {
...
} finally {
...
}
....
#此处回收
msg.recycleUnchecked();
}
} private static boolean gCheckRecycle = true; #标识是否检测回收
# Android版本低于Lollipop不检测回收
public static void updateCheckRecycle(int targetSdkVersion) {
if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
gCheckRecycle = false;
}
}
/*package*/ boolean isInUse() {
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
public void recycle() {
if (isInUse()) { #检测时候在适使用
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}recycle方法首先检测对象是否正在使用,是否在使用的状态上面已经提到了,入队正在处理,或者在回收池内。如果检测到正在使用,在判断gCheckRecycle是否检测回收,gCheckRecycle初始默认值是true,在updateCheckRecyle方法内判断修改其值,而updateCheckRecycle方法实在ActivityThread的handlebindApplication方法启动app时调用的:
private void handleBindApplication(AppBindData data) {
....
// send up app name; do this *before* waiting for debugger
Process.setArgV0(data.processName);
#这里对Message的gCheckRecycle修改
Message.updateCheckRecycle(data.appInfo.targetSdkVersion);
...
}Message默认都是同步消息,在某些操作中,比如View的invalidate,会使用同步消息屏障,阻止后续消息达到某个条件才执行,异步消息能够让消息不受Looper的同步消息屏障的影响,免于消息屏障,异步消息的典型代表有中断、输入事件和其他即使有以他工作要被挂起也要单独执行的信号,如果消息被设置成异步的,会优先执行。Message中设置消息是否为异步的方法是setAsynchronous()
public void setAsynchronous(boolean async) {
if (async) {
flags |= FLAG_ASYNCHRONOUS;
} else {
flags &= ~FLAG_ASYNCHRONOUS;
}
}上面方法通过逻辑操作符修改flags,也提供了判断消息是否是异步的方法:
public boolean isAsynchronous() {
return (flags & FLAG_ASYNCHRONOUS) != 0;
}Message是安卓消息传递机制信息的载体,他内部维护了一个链表,指向下一个,维护了一个缓存队列,最多缓存50个对象,避免重复创建对象,Message回收使用了享元模式的设计模式,Message回收会把flags标识成FLAG_IN_USE,消息入队也会标识成IN_USE,获取Message对象一般使用Message.obtain()方法,内部会清空flags标识。
本文为Adamin90原创文章,转载无需和我联系,但请注明来自http://www.lixiaopeng.top
你的糖罐呢:真不戳
2021-09-16 14:43:45 回复