问题
模拟一下项目中遇到的场景,handeMessage处理消息时,没有立即获取消息内容,而是在处理耗时逻辑后获取,结果msg.obj为null, arg1为0,代码如下
handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
switch (msg.what) {
case 2000:
showDialog(msg);
break;
case 3000:
showDialog(msg);
break;
}
return false;
}
});
对话框点击确定后打印消息的内容
private void showDialog(Message message) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示");
builder.setMessage("这是一个AlertDialog示例");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// 点击确定按钮的处理逻辑
Log.i(TAG, "dialog: what " + message.what + ", obj " + message.obj + ", arg " + message.arg1);
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// 点击取消按钮的处理逻辑
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
发送消息
Message message = Message.obtain();
message.what = 2000;
message.obj = "obtain message";
message.arg1 = 1;
handler.sendMessage(message);
结果打印
Main: dialog: what 0, obj null, arg 0
分析
// Looper
public static void loop() {
final Looper me = myLooper();
// 。。。省略
for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}
// ...
try {
// 分发消息
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
//...
throw exception;
} finally {
//...
}
// ...
// 回收消息
msg.recycleUnchecked();
//...
}
原因在于Looper循环取出消息时,在调用msg.target.dispatchMessage(msg)后,会调用msg.recycleUnchecked()来回收该消息
注:
msg.target , 指向的是发送该消息的handler
dispatchMessge, 最后会调用我们代码里重写的handleMessage
所以呢,在上面的对话框里点击确定后获取msg的内容时,它早就已经被回收啦!
--------------------------------------------------------------分割线----------------------------------------------------------
看看Message的recycleUnchecked方法,会重置对象的值,并把它加入消息池当中,循环使用。(ps:消息池可以避免重复创建对象,节约内存)
// 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 = 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++;
}
}
}
结论
当处理完消息之后,message的内容会重置,并放入消息池当中,所以我们在一定时延后获取到的消息内容会变为空。
如有需要,可以先用其他变量接收message的值。