Android中的处理程序和内存泄漏

请看下面的代码:

public class MyGridFragment extends Fragment{
Handler myhandler = new Handler() {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case 2: {
ArrayList> theurls = (ArrayList>) message.obj;
urls.addAll(theurls);
theimageAdapter.notifyDataSetChanged();
dismissBusyDialog();
break;
}}}};
}

当我使用这样的处理程序时,我会收到一条警告:“处理程序应该是静态的,否则很容易发生内存泄漏。” 有人可以告诉我什么是最好的方法吗?

Rasmus asked 2020-06-21T12:43:12Z

6个解决方案

100 votes

我最近在自己的代码中更新了类似内容。 我只是使匿名Handler类成为受保护的内部类,而Lint警告消失了。 看看下面的代码是否适合您:

public class MyGridFragment extends Fragment{
static class MyInnerHandler extends Handler{
WeakReference mFrag;
MyInnerHandler(MyGridFragment aFragment) {
mFrag = new WeakReference(aFragment);
}
@Override
public void handleMessage(Message message) {
MyGridFragment theFrag = mFrag.get();
switch (message.what) {
case 2:
ArrayList> theurls = (ArrayList>) message.obj;
theFrag.urls.addAll(theurls);
theFrag.theimageAdapter.notifyDataSetChanged();
theFrag.dismissBusyDialog();
break;
}//end switch
}
}
MyInnerHandler myHandler = new MyInnerHandler(this);
}

您可能需要更改放置“ theFrag”的位置。 我只能猜测那些引用的内容。

Uncle Code Monkey answered 2020-06-21T12:43:49Z
11 votes

这是我制作的一个有用的小类,您可以使用。 可悲的是它仍然很冗长,因为您不能拥有匿名的静态内部类。

import java.lang.ref.WeakReference;
import android.os.Handler;
import android.os.Message;
/** A handler which keeps a weak reference to a fragment. According to
* Android's lint, references to Handlers can be kept around for a long
* time - longer than Fragments for example. So we should use handlers
* that don't have strong references to the things they are handling for.
*
* You can use this class to more or less forget about that requirement.
* Unfortunately you can have anonymous static inner classes, so it is a
* little more verbose.
*
* Example use:
*
* private static class MsgHandler extends WeakReferenceHandler
* {
* public MsgHandler(MyFragment fragment) { super(fragment); }
*
* @Override
* public void handleMessage(MyFragment fragment, Message msg)
* {
* fragment.doStuff(msg.arg1);
* }
* }
*
* // ...
* MsgHandler handler = new MsgHandler(this);
*/
public abstract class WeakReferenceHandler extends Handler
{
private WeakReference mReference;
public WeakReferenceHandler(T reference)
{
mReference = new WeakReference(reference);
}
@Override
public void handleMessage(Message msg)
{
if (mReference.get() == null)
return;
handleMessage(mReference.get(), msg);
}
protected abstract void handleMessage(T reference, Message msg);
}
Timmmm answered 2020-06-21T12:44:09Z
5 votes

根据ADT 20更改,您似乎应该将其设为静态。

新皮棉检查:

检查以确保Fragment类是可实例化的。 如果您不小心使 片段内部类是非静态的,或者忘记具有默认构造函数,则可以运行时 系统在更改配置后尝试重新实例化片段时发生错误。

查找处理程序泄漏:此检查可确保处理程序内部类不持有 隐式引用其外部类。

Geobits answered 2020-06-21T12:44:43Z

4 votes

如果您阅读有关AccountManager或PendingIntent的文档,将会看到某些方法将Handler作为参数之一。

例如:

onFinished-发送完成后要回调的对象;如果没有回调,则为null。

handler-标识应在其上进行回调的线程的处理程序。 如果为null,则回调将从进程的线程池发生。

想象一下情况。 一些Activity调用PendingIntent.send(...)并放置Handler的非静态内部子类。 然后活动被破坏。 但是内部阶级生活。

内部类仍然拥有指向已破坏活动的链接,无法对其进行垃圾收集。

如果您不打算将处理程序发送给此类方法,则无需担心。

QuickNick answered 2020-06-21T12:45:30Z

0 votes

我遇到了同样的问题,我发现它是该主题之一,有很多问题,很少回答。 我的解决方案很简单,希望可以对某人有所帮助:

/* BEFORE */
private Handler mHandler= new Handler() {
@Override public void handleMessage(Message msg) {
this.doSomething();
};
};

我们可以创建一个仅运行Runnable的静态Handler子类。 实际的处理程序实例将知道通过可访问实例变量的可运行对象做什么。

/* AFTER */
static class RunnableHandler extends Handler {
private Runnable mRunnable;
public RunnableHandler(Runnable runnable) {
mRunnable = runnable;
}
@Override public void handleMessage(Message msg) {
mRunnable.run();
};
}
private RunnableHandler mHandler = new RunnableHandler(new Runnable() {
@Override public void run() {
this.doSomething();
} });

功能相同时,警告消失。

blurkidi answered 2020-06-21T12:45:59Z
0 votes

针对这种情况的简单解决方案可能是:

Handler handler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
//do your stuff here
return false;
} });
StartCoding answered 2020-06-21T12:46:19Z