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
- Cómo probar un IntentService utilizando un ServiceTestCase?
- Android: Mostrar Notificación en la Vigilancia Cuando Cualquier Llamada o Notificación de la Red Social de móvil (mediante Bluetooth)
- Mantenga el servicio de ubicación activo cuando la aplicación esté cerrada.
- Implementar la devolución de llamada de Servicio a Actividad
- ¿Cómo seguir reproduciendo música en segundo plano después de que el usuario haga desaparecer la aplicación?
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(); }
- Android - vinculante para el servicio
- Servicio o Thread o AsyncTask
- No obtener el valor actualizado de la preferencia compartida en el servicio
- Obtenga la ubicación de Android GPS una vez cada pocos minutos
- Servicio de Android interactuando con múltiples actividades
- Hacer que Android Service escuche Hardware-Key Press Events
- Servicio v / s AsyncTask
- IntentService - encuentra el número de Intents esperando en la cola
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 suThread
sólo sirve unaActivity
, pase la referencia deActivity
junto con la referencia delHandler
en la construcción de suThread
(Runnable
). - Antes de que su
Thread
envíe el mensaje a través del controlador, marqueactivity.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 delRunnable
run()
deRunnable
o defina su referencia deActivity
ennull
si descubre que laActivity
ha sido destruida.
Esto debería corregir el código anterior. Sin embargo, si su escenario crece, otros enfoques pueden ser más adecuados.
- Edittext cursor restablecer a la izquierda después de la actualización de datos de datos de Android
- Hacer que la vista web de una tableta simule un pequeño dispositivo