Обработчики и утечки памяти в Android

пожалуйста, посмотрите на код ниже:

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;
        }}}};
         }

когда я использую такой обработчик, я получаю предупреждение "обработчик должен быть статическим, иначе он подвержен утечкам памяти."Может кто-нибудь сказать мне, как лучше всего это сделать?

6 ответов


недавно я обновил что-то подобное в своем собственном коде. Я просто сделал анонимный класс обработчика защищенным внутренним классом, и предупреждение 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);
}

возможно, вам придется изменить, где я поставил " theFrag.- как я могу только догадываться, на что они ссылаются.


вот несколько полезный маленький класс, который я сделал, который вы можете использовать. К сожалению, это все еще довольно многословно, потому что вы не можете иметь анонимные статические внутренние классы.

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);
}

на ADT 20 изменения, похоже, вы должны сделать его статическим.

Новые Проверки Корпии:

проверьте, чтобы убедиться, что фрагмент занятия instantiatable. Если вы случайно фрагмент innerclass нестатический или забудьте иметь конструктор по умолчанию, вы можете нажать runtime ошибки при попытке системы восстановить фрагмент после изменения конфигурации.

ищите утечки обработчика: эта проверка делает убедитесь, что внутренний класс обработчика не содержит неявная ссылка на его внешний класс.


Если Вы читаете документы об AccountManager или PendingIntent, вы увидите, что некоторые методы принимают обработчик в качестве одного из аргументов.

:

  • onFinished-объект для обратного вызова, когда отправка завершена, или null для Без обратного вызова.
  • обработчик - обработчик, определяющий поток, на котором должен произойти обратный вызов. Если null, обратный вызов произойдет из пула потоков процесс.

Представьте ситуацию. Некоторые действия называют PendingIntent.посылать.(..) и поместите нестатический внутренний подкласс Handler. И тогда активность уничтожается. Но внутренний класс живет.

внутренний класс по-прежнему содержит ссылку на уничтоженную активность, она не может быть собрана мусора.

Если вы не планируете отправлять обработчик таким методам, вам не о чем беспокоиться.


я сталкиваюсь с той же проблемой, и я нахожу, что это одна из этих тем со многими вопросами и несколькими ответами. Мое решение простое, и я надеюсь, что это может помочь кому-то:

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

мы можем создать статический подкласс обработчика, который просто запускает Runnable. Фактический экземпляр обработчика будет знать, что делать через 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();
    } });

предупреждение исчезло, а дата та же.


простым решением для этого случая может быть:

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