此消息无法回收,因为它仍在使用中

Pit*_*tel 6 android android-handler

我正在尝试使用这篇文章来创建异步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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

And*_*lov 7

首先,让我们看看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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

boolean isInUse() {
        return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
    }
Run Code Online (Sandbox Code Playgroud)

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

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

当邮件入队时设置此标志,并在邮件传送时保持设置,之后再循环.只有在创建或获取新消息时才会清除该标志,因为这是允许应用程序修改消息内容的唯一时间.

尝试排队或回收已在使用的邮件是错误的.

那么我们有什么

  1. 你不能回收消息,直到它"正在使用"
  2. 它在"使用中",直到获得或创建新消息

如何解决问题

recycleUnchecked()Message类中有一个方法可以回收消息对象,即使它正在使用中.这就是你需要的东西!说明:

重新循环可能正在使用的消息.

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

最糟糕的是它在内部使用并具有包访问权限.当你打电话时它在内部使用的好东西:

handler.removeMessages(int what)
Run Code Online (Sandbox Code Playgroud)

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

更换

msg.recycle();
Run Code Online (Sandbox Code Playgroud)

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