问题记录 Android Handler——处理消息时,取出的message的obj为null?

问题

模拟一下项目中遇到的场景,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的值。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值