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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11278875/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 06:41:42  来源:igfitidea点击:

Handlers and memory leaks in Android

androidhandler

提问by Rasmus

Please have a look at the code below:

请看下面的代码:

public class MyGridFragment extends Fragment{

     Handler myhandler = new Handler() {
    @Override
    public void handleMessage(Message message) {
        switch (message.what) {
        case 2: {

            ArrayList<HashMap<String,String>> theurls = (ArrayList<HashMap<String,String>>) message.obj;
            urls.addAll(theurls);
            theimageAdapter.notifyDataSetChanged();
            dismissBusyDialog();
            break;
        }}}};
         }

When I use handler like this I get a warning "handler should be static, else it is prone to memory leaks." Can someone tell me what is the best way to do this?

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

回答by Uncle Code Monkey

I recently updated something similar in my own code. I just made the anonymous Handler class a protected inner class and the Lint warning went away. See if something like the below code will work for you:

我最近在自己的代码中更新了类似的东西。我只是将匿名处理程序类设为受保护的内部类,然后 Lint 警告消失了。看看下面的代码是否适合你:

public class MyGridFragment extends Fragment{

    static class MyInnerHandler extends Handler{
        WeakReference<MyGridFragment> mFrag;

        MyInnerHandler(MyGridFragment aFragment) {
            mFrag = new WeakReference<MyGridFragment>(aFragment);
        }

        @Override
        public void handleMessage(Message message) {
            MyGridFragment theFrag = mFrag.get();
            switch (message.what) {
            case 2:
                ArrayList<HashMap<String,String>> theurls = (ArrayList<HashMap<String,String>>) message.obj;
                theFrag.urls.addAll(theurls);
                theFrag.theimageAdapter.notifyDataSetChanged();
                theFrag.dismissBusyDialog();
                break;
            }//end switch
        }
    }
    MyInnerHandler myHandler = new MyInnerHandler(this);
}

You may have to change where I put "theFrag." as I could only guess as to what those referenced.

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

回答by Timmmm

Here's a somewhat useful little class I made that you can use. Sadly it's still quite verbose because you can't have anonymous static inner classes.

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

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<MyFragment>
 *  {
 *      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<T> extends Handler
{
    private WeakReference<T> mReference;

    public WeakReferenceHandler(T reference)
    {
        mReference = new WeakReference<T>(reference);
    }

    @Override
    public void handleMessage(Message msg)
    {
        if (mReference.get() == null)
            return;
        handleMessage(mReference.get(), msg);
    }

    protected abstract void handleMessage(T reference, Message msg);
}

回答by Geobits

Per the ADT 20 Changes, it looks like you should make it static.

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

New Lint Checks:

Check to make sure that Fragment classes are instantiatable. If you accidentally make a fragment innerclass non-static, or forget to have a default constructor, you can hit runtime errors when the system attempts to reinstantiate your fragment after a configuration change.

Look for handler leaks: This check makes sure that a handler inner class does not hold an implicit reference to its outer class.

新的皮棉检查:

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

查找处理程序泄漏:此检查确保处理程序内部类不包含对其外部类的隐式引用。

回答by QuickNick

If you read docs about AccountManager or PendingIntent, you will see that some methods take Handler as one of arguments.

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

For example:

例如

  • onFinished - The object to call back on when the send has completed, or null for no callback.
  • handler - Handler identifying the thread on which the callback should happen. If null, the callback will happen from the thread pool of the process.
  • onFinished - 发送完成时回调的对象,或者 null 表示没有回调。
  • handler -标识应该发生回调的线程的处理程序。如果为 null,则回调将从进程的线程池中发生。

Imagine the situation. Some Activity calls PendingIntent.send(...) and put the non-static inner subclass of Handler. And then activity is destroyed. But inner class lives.

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

Inner class still holds a link to destroyed activity, it cannot be garbage-collected.

内部类仍然持有一个指向被销毁活动的链接,它不能被垃圾收集。

If you're not planning to send your handler to such methods, you have nothing to worry about.

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

回答by blurkidi

I run into the same issue and I find that it is one of this topics with many questions and few answeres. My solution is simple and I hope it can help someone:

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

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

We can create a static Handler subclass that simply runs a Runnable. The actual handler instance will know what to do through the runnable that will have access to instance variables.

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

/* 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();
    } });

The warning is gone while the funcionality is the same.

警告消失,而功能相同。

回答by StartCoding

A simple solution for this case might be:

对于这种情况,一个简单的解决方案可能是:

Handler handler=new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message message) {
        //do your stuff here
        return false;
    } });