Обработчики и утечки памяти в 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; }}}}; } 

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

Solutions Collecting From Web of "Обработчики и утечки памяти в Android"

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

Новые проверки Lint:

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

Посмотрите на утечки обработчиков. Эта проверка гарантирует, что внутренний класс обработчика не содержит неявной ссылки на его внешний класс.

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

Например :

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

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

Внутренний класс по-прежнему содержит ссылку на разрушенную деятельность, ее нельзя собирать с мусором.

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

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

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

Мы можем создать статический подкласс класса Handler, который просто запускает 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(); } }); 

Предупреждение уходит, а функциональность – то же самое.