La instancia de actividad sigue existiendo incluso después de que onDestroy () se llame

Paso un controlador creado en el hilo principal de la Activity y pasado a un hilo que realiza alguna operación de red y cuando obtengo el resultado devuelvo el resultado a la actividad usando el manejador.

Este enfoque tuvo problemas en fugas de memoria cuando pasé por estos enlaces:
Inner ClassHandler Memory Leak
Desarrolladores de Android

Así que había implementado WeakReference , y mantuvo la instancia de actividad utilizando WeakReference . Pero todavía estoy viendo la instancia de Activity vivo incluso después de que la actividad se destruye.

Creé un controlador dentro de la actividad y pasó instancia de actividad como weakreference a manejador.
En el momento en que mi Handler responda con un mensaje enviado después de 10 segundos, la Activity se destruye. Pero la referencia débil todavía tiene la instancia de Activity y estoy viendo el Toast , después de que la Activity se destruye.

¿Hay algún lugar donde mi comprensión mal?
¿Puede alguien explicar cómo manejar los mensajes entregados a un manejador, pero la interfaz de usuario no está alrededor?

 import java.lang.ref.WeakReference; import android.os.Handler; import android.os.Message; public abstract class SingleParamHandler <T> extends Handler { private WeakReference<T> mActivityReference; public SingleParamHandler(T activity) { mActivityReference = new WeakReference<T>(activity); } @Override public void handleMessage(Message msg) { if (mActivityReference.get() == null) { return; } handleMessage(mActivityReference.get(), msg); } protected abstract void handleMessage(T activity, Message msg); } import android.app.Activity; import android.os.Bundle; import android.os.Message; import android.widget.Toast; public class MainActivity extends Activity { MyHandler<MainActivity> handler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main1); handler = new MyHandler<MainActivity>(this); new Thread(new MyRunnable(handler)).start(); } public void onDestroy() { super.onDestroy(); System.out.println("######## Activity onDestroy() ###### "); } private class MyRunnable implements Runnable { private Handler mHandler; public MyRunnable(Handler handler) { mHandler = handler; } public void run() { try { Thread.sleep(10000); mHandler.sendMessage(Message.obtain(handler, 1)); } catch ( Exception e) { e.printStackTrace(); } } } private static class MyHandler<T> extends SingleParamHandler<T> { public MyHandler(T activity) { super(activity); } @Override public void handleMessage(T act, Message msg) { if(msg.what == 1) { Toast.makeText((MainActivity)act, "Called after activity destroyed", Toast.LENGTH_LONG).show();; } } } } 

Sobre la base de la respuesta obtenida , estoy actualizando la respuesta aquí. Usted puede hacerlo de la manera u gustado. Pero esta es una forma.

Se agregó la siguiente función en SingleParamHandler

 public void clear() { mActivityReference.clear(); } 

Y en Actividad onDestroy ()

 public void onDestroy() { super.onDestroy(); System.out.println("######## Activity onDestroy() ###### "); handler.clear(); } 

No necesitas una WeakReference aquí. El Handler sólo puede contener una referencia a la Activity . En el onDestroy() la actividad, simplemente llame a un método en MyHandler que establece la referencia a la Activity como null . Compruebe si hay null en handleMessage() .

Otra opción sería esto: en la actividad onDestroy() llama a un método que interrumpe el hilo de dormir para que se apague antes de enviar el mensaje.

No hay garantía de que Android realmente elimine un objeto de la memoria si no es necesario hacerlo. En otras palabras, los objetos Activity pueden permanecer en la memoria incluso después de que onDestroy() haya sido llamado (si hay suficiente memoria disponible). Por otro lado, no hay garantía de que onDestroy() será llamado si no hay suficiente memoria; Bastante por el contrario, Android se permite matar todo el proceso después de llamar onPause() en su actividad actual (dependiendo de la versión de Android).

Creo que hay un camino mejor a seguir para su propósito. Lo que puede querer hacer es adjuntar , desacoplar y posiblemente volver a conectar (por ejemplo, sobre cambios de configuración) Actividades a su Servicio. No esperes que el recolector de basura haga el trabajo por ti. Más bien, hacerlo explícitamente.

Subclase Activity y reemplaza los métodos del ciclo de vida, así como startActivity() y startActivityForResult() para que su Servicio sepa quién está a cargo en este momento. Por supuesto, eso es sólo un enfoque de mejor esfuerzo ya que algunas devoluciones de llamada no están garantizadas, pero eso sólo importa en ciertas situaciones que no son peligrosas. Por ejemplo, su Actividad no se separará de su Servicio en onPause() , pero podría matarse inmediatamente después. Sin embargo, o bien su servicio se ejecuta en el mismo proceso, por lo que se mata al mismo tiempo. O se ejecuta en un proceso diferente, pero luego Android se dará cuenta de la conexión roto y puede o no matar el servicio también, Si no, entonces todo lo que necesita hacer es implementarlo de una manera robusta para poder hacer frente a la pérdida de conexión.

Actualizar

Después de leer su comentario: Tienes razón, no me referí específicamente a eso.

Estoy averiguando cómo evitar los mensajes que se envían a un manejador que se crea en una actividad que se destruye

Dado su código anterior, y suponiendo que realmente sólo desea mostrar Toast s con una actividad, siempre y cuando exista, el siguiente enfoque debería ayudar.

  • Si se supone que su Thread sirve para más de una Actividad, extiéndala para que las Actividades puedan registrarse con el Tema después de que se cree. Si su Thread sólo sirve una Activity , pase la referencia de Activity junto con la referencia del Handler en la construcción de su Thread ( Runnable ).
  • Antes de que su Thread envíe el mensaje a través del controlador, marque activity.isDestroyed() . Si la actividad no se destruye, envíe el mensaje. Si la actividad se destruye, no envíe el mensaje.
  • Dependiendo de si su hilo debe Runnable más de una actividad, o bien salga del Runnable run() de Runnable o defina su referencia de Activity en null si descubre que la Activity ha sido destruida.

Esto debería corregir el código anterior. Sin embargo, si su escenario crece, otros enfoques pueden ser más adecuados.

  • ¿Debo usar Service o IntentService para mi aplicación android?
  • El servicio de larga duración consume mucha batería
  • Iniciar VPNService desde dentro de widget android
  • Asynctask vs. Thread vs Services vs Loader
  • START_STICKY para IntentService
  • Iniciar / Detener servicio desde Widget
  • Parte-1 persistente foreGround servicio androide que comienza por la interfaz de usuario, funciona en modo de suspensión también, también comienza en el reinicio del teléfono
  • ¿Cómo puede el servicio de Android actualizar la interfaz de usuario de la actividad que lo inició?
  • Tomar la foto de la cámara sin vista previa
  • Iniciar la aplicación de Android sin actividad principal e iniciar el servicio al iniciar la aplicación
  • Android proceso remoto: messenger vs aidl? ¿Cual es mejor?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.