【问题标题】:This message cannot be recycled because it is still in use此消息无法回收,因为它仍在使用中
【发布时间】:2017-10-16 15:07:39
【问题描述】:

我正在尝试使用 this article 创建异步 UDP 套接字。

所以我有这个代码:

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;

import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpThread
    extends HandlerThread {

    private static final String TAG = "UDP";
    private final Handler uiHandler, workerHandler;
    private final DatagramSocket socket = new DatagramSocket();

    public UdpThread(final Handler uiHandler, final String hostname, final int port) throws SocketException {
        super(TAG);
        this.uiHandler = uiHandler;
        start();
        workerHandler = new Handler(getLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(final Message msg) {
                /*
                if (msg.what == port && msg.obj == hostname) {
                    final InetSocketAddress address = new InetSocketAddress(hostname, port);
                    Log.d(TAG, "Connecting to " + address);
                    try {
                        socket.connect(address);
                    } catch (SocketException se) {
                        throw new RuntimeException(se);
                    }
                }
                */
                msg.recycle(); //java.lang.IllegalStateException: This message cannot be recycled because it is still in use.
                return true;
            }
        });
        workerHandler.obtainMessage(port, hostname).sendToTarget();
    }
}

但是当我运行代码时,我在尝试回收消息时得到了提到的java.lang.IllegalStateException: This message cannot be recycled because it is still in use.。为什么会这样以及如何解决它并防止内存泄漏?

【问题讨论】:

  • 我认为你不必使用回收
  • 这似乎是正确的。即使我开始发送垃圾邮件,内存消耗似乎也很平稳。

标签: android android-handler


【解决方案1】:

首先让我们看看Message recycle() 方法是如何工作的。

public void recycle() {
    if (isInUse()) {
        if (gCheckRecycle) {
            throw new IllegalStateException("This message cannot be recycled because it "
                    + "is still in use.");
        }
        return;
    }
    recycleUnchecked();
}

所以你会得到IllegalStateException,如果它正在使用中

isInUse() 只是检查标志,看起来像:

boolean isInUse() {
        return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
    }

当我们尝试阅读该标志时,我们会看到描述:

如果设置消息正在使用中。

此标志在消息入队时设置,并在消息入队时保持设置 交付后,当它被回收时。国旗只是 在创建或获取新消息时清除,因为那是 仅允许应用程序修改 消息。

尝试将消息排入队列或回收是错误的 已经在使用了。

我们有什么

  1. 在“正在使用”之前,您无法回收消息
  2. 在获得或创建新消息之前一直处于“使用中”

如何解决问题

Message 类中有recycleUnchecked() 方法可以回收消息对象甚至,如果它正在使用中。这就是你所需要的!描述:

回收可能正在使用的消息。

在处理时由 MessageQueue 和 Looper 内部使用 排队的消息。

它在内部使用并具有包访问权限的最糟糕的事情。调用时它在内部使用的好东西:

handler.removeMessages(int what)

所以我想最终的解决方案是:

替换

msg.recycle();

try {
     msg.recycle(); //it can work in some situations
} catch (IllegalStateException e) {
     workerHandler.removeMessages(msg.what); //if recycle doesnt work we do it manually
}

【讨论】:

    【解决方案2】:

    您不应该自己调用msg.recycle(),消息在发送/处理后(在您的handleMessage() 返回后)会被 Looper 自动回收,请参阅source code

    【讨论】:

      【解决方案3】:

      尝试使用AsyncTask 删除消息,当处理程序线程完成继续它。

      //[..]
              //synchronized with the handler thread
              @Override
              public boolean handleMessage(final Message msg) {
                  new MessageDestructor().execute(msg);
                  return true;
              }
      //[..]
      private class MessageDestructor extends AsyncTask<Message, Void, Void> {
          Message msg;
          @Override
          protected String doInBackground(Message... params) {
              msg = (Message) params[0]; 
              return null;
          }
      
          @Override
          protected void onPostExecute(Void result) {
             msg.recycle(); //synchronized with the main thread
          }
      
          @Override
          protected void onPreExecute() {
          }
      
          @Override
          protected void onProgressUpdate(Void... values) {
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-25
        • 1970-01-01
        相关资源
        最近更新 更多