Controladores y pérdidas de memoria en Android

Por favor, eche un vistazo al código a continuación:

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

Cuando utilizo Handler de esta manera, aparece una advertencia: “el manejador debe ser estático, de lo contrario es propenso a pérdidas de memoria”. ¿Puede alguien decirme cuál es la mejor manera de hacer esto?

Recientemente, actualicé algo similar en mi propio código. Acabo de convertir la clase anónima de Handler en una clase interna protegida y la advertencia de Lint desapareció. Vea si algo como el siguiente código le funcionará:

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

Puede que tenga que cambiar dónde puse “theFrag”. como solo pude adivinar a qué se referían.

Aquí hay una pequeña clase algo útil que hice que puedes usar. Tristemente todavía es bastante detallado porque no puedes tener clases internas estáticas anónimas.

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

Según el ADT 20 Cambios , parece que debes hacerlo estático.

Nuevos controles de pelusa:

Verifique para asegurarse de que las clases de Fragment sean instanciables. Si hace accidentalmente un fragmento de clase interna no estático, u olvida tener un constructor predeterminado, puede golpear los errores de tiempo de ejecución cuando el sistema intente reinstalar su fragmento después de un cambio de configuración.

Busque fugas del controlador: esta comprobación se asegura de que una clase interna del controlador no contenga una referencia implícita a su clase externa.

Si lee documentos sobre AccountManager o PendingIntent, verá que algunos métodos toman Handler como uno de los argumentos.

Por ejemplo :

  • onFinished: el objeto para volver a llamar cuando se ha completado el envío, o nulo para la callback.
  • controlador: identificador que identifica el hilo sobre el que debe producirse la callback . Si es nulo, la callback se realizará desde el grupo de subprocesos del proceso.

Imagina la situación Algunas actividades llaman a PendingIntent.send (…) y ponen la subclase interna no estática de Handler. Y luego la actividad se destruye. Pero la clase interna vive.

La clase interna todavía tiene un enlace a la actividad destruida, no puede ser recolectada.

Si no planea enviar a su controlador a tales métodos, no tiene nada de qué preocuparse.

Me encuentro con el mismo problema y encuentro que es uno de estos temas con muchas preguntas y pocas respuestas. Mi solución es simple y espero que pueda ayudar a alguien:

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

Podemos crear una subclase Handler estática que simplemente ejecuta Runnable. La instancia del controlador real sabrá qué hacer a través del ejecutable que tendrá acceso a las variables de instancia.

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

La advertencia se ha ido mientras la funcionalidad es la misma.