1. Message的重要属性
Each Handler has its own name-space for message codes, so you do not need to worry about yours conflicting with other handlers. 每个Handler都有自己命名空间的消息码,这样不必担心和其它Handler冲突。
每个Handler只处理自家的Message, 但Message是如何区分Handler呢?
这就需要我们考虑去将Message 和 Handler 进行绑定。
我们查看Message的源码,会发现有一个成员变量:
Handler target;
当我们查看Message中各个obtain()方法,都会发现与target进行绑定(特殊的obtain()可以进一步查看Handler,其最终也是要对target进行绑定的,这里不再展开)。
public static Message obtain(Handler h, int what,
int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
m.obj = obj;
return m;
}
除了target ,还有:
Runnable callback
public long when;
关于Handler的更多详情 Handler的前世今生4——Handler
2. Message 的obtain()
官方建议我们在发送消息尽量使用obtain(),我们来看一下obtain()的实现:
从全局的消息池中给我们返回一个新的Message实例,很多情况下可以避免我们新建对象。
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
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();
我们通过进一步的分析Message的成员变量:
Message next;
private static Message sPool;
public static final Object sPoolSync = new Object(); // 全局锁对象
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
这就告诉我们,Message是链表设计,Message池的最大数量为50.
3. Message的回收
FLAG_IN_USE 标记消息在使用中,当消息进入队列或者复用时都被被置为该状态。
/** If set message is in use.
* This flag is set when the message is enqueued and remains set while it
* is delivered and afterwards when it is recycled. The flag is only cleared
* when a new message is created or obtained since that is the only time that
* applications are allowed to modify the contents of the message.
*
* It is an error to attempt to enqueue or recycle a message that is already in use.
*/
static final int FLAG_IN_USE = 1 << 0;
recyclerUnchecked()方法是用来复用消息的。这里主要就是对消息的属性恢复默认,其判断消息池是否溢出。我们在Looper的loop()方法看过它的身影。
/**
* Recycles a Message that may be in-use.
* Used internally by the MessageQueue and Looper when disposing of queued Messages.
*/
@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) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
我们还看到一个recycle() 方法:
public void recycle() {
if (isInUse()) {
if (gCheckRecycle) {
throw new IllegalStateException("This message cannot be recycled because it "
+ "is still in use.");
}
return;
}
recycleUnchecked();
}
有没有似曾相识的感觉,你在处理Bitmap时…(PS:Bitmap类中也有一个recycle()方法)。在涉及到复用的情况下,基本都会出现该方法的身影。
为什么Looper的loop()方法调用的是recycleUnchecked()呢?
个人认为是:loop()中可以保证消息一定没有在使用,完全没有必要判断isInUse(),所以直接调用了recycleUnchecked()。
OK ,关于Message的内容就介绍到这里…
欢迎继续收看 Handler的前世今生4 —— Handler