Android安卓handler message消息msg.arg1、msg.arg1和msg.obj变零0或者变null空的问题解决方案

今天遇到一个奇怪的问题,使用安卓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值赋给一个新的变量问题就解决了!

欢迎评论点赞收藏!您的支持是我创作的动力!

原创文章 23 获赞 31 访问量 4万+

猜你喜欢

转载自blog.csdn.net/ldkjsdty/article/details/106011676
今日推荐