今天遇到一个奇怪的问题,使用安卓Handler消息发送数据进行处理,结果拿到的msg.arg1竟然偶尔变0,不是每次都是0,是偶发性的,我的代码是类似于这样的:
...
case HandlerMsgId:
System.out.println("编号1消息:"+msg.arg1);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("编号2消息:"+msg.arg1);
}
}).start();
msg.arg1设置发送的值为1,输出结果有时候是这样的:
编号1消息:1
编号2消息:1
上面这个结果是期望的结果,但是有时候却是这样的:
编号1消息:1
编号2消息:0
子线程中的 msg.arg1竟然变成了0!
通过查看源码分析发现了问题的原因,原来是因为当执行Handler消息的主线程执行完handleMessage(android.os.Message msg)后会对msg对象进行回收利用,把msg持有的变量重置了,因为子线程的创建执行有一定延迟,这个重置执行在子线程执行完毕之前,引发了线程不安全导致的问题,源码分析如下:
查看Looper.class可以看到有这样一段代码:
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
//发送消息,内部方法进行了调用你重写的 handleMessage(Message msg)方法
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
//回收利用msg,下面重点展开
msg.recycle();
}
}
msg.recycle();方法是用于回收利用msg的,点进去有个clearForRecycle()方法,clearForRecycle()可以看到里面有一段这样的代码:
void clearForRecycle() {
flags = 0;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
when = 0;
target = null;
callback = null;
data = null;
}
这时明白了为什么arg1 会变0了。
解决方案:代码如下:
...
case HandlerMsgId:
System.out.println("编号1消息:"+msg.arg1);
final int i = msg.arg1;
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("编号2消息:"+i);
}
}).start();
把msg.arg1值赋给一个新的变量问题就解决了!
欢迎评论点赞收藏!您的支持是我创作的动力!