¿Es posible que un método de devolución de llamada se llame después de onDestroy?

En la última versión de mi aplicación, algunos usuarios experimentan un bloqueo que no puedo reproducir. Actualmente sólo los dispositivos Samsung que ejecutan Lollipop están teniendo el problema, pero eso podría ser una coincidencia. Después de analizar el rastro de la pila y el código relevante, creo que podría haber encontrado al culpable. Para probar mi suposición, simplifiqué el código al siguiente fragmento:

 public class TestActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Button b = new Button(this); b.setText("Click me!"); b.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Handler().post(new Runnable() { @Override public void run() { // This is the callback method Log.d("TAG", "listenerNotified"); } }); } }); setContentView(b); } @Override protected void onDestroy() { super.onDestroy(); Log.d("TAG", "onDestroy"); } } 

Cada vez que pruebo la aplicación anterior haciendo primero clic en el botón Click me y luego en el botón back, listenerNotified se imprime en la consola antes onDestroy() .

Sin embargo, no estoy seguro si puedo confiar en este comportamiento. ¿Tiene Android alguna garantía sobre el escenario anterior? ¿Puedo asumir con seguridad que mi Runnable siempre se ejecutará antes onDestroy() o hay un escenario en el que no será el caso? En mi aplicación real, hay, por supuesto, mucho más sucediendo (como otros hilos de publicar en el hilo principal y más operaciones que suceden en la devolución de llamada). Pero este simple fragmento parecía suficiente para demostrar mi preocupación.

¿Es todo posible (posiblemente debido a la influencia de otros hilos o devoluciones de llamada publicado en el hilo principal) que obtengo la salida de depuración a continuación?

 D/TAG: onDestroy D/TAG: listenerNotified 

Me gustaría saber esto, ya que ese resultado posible sería explicar el accidente.

¿Es posible que un método de devolución de llamada se llame después de onDestroy() ?

Sí.

Cambiemos un poco su código de ejemplo con respecto a la publicación de un Runnable al Handler . También asumo (de acuerdo con su descripción) que puede tener varios Runnable s publicado en el hilo principal, por lo que en algún momento puede haber una cola de Runnable s que me lleva a un retraso en el experimento a continuación:

 public void onClick(View view) { new Handler().postDelayed(new Runnable() { @Override public void run() { // This is the callback method Log.d("TAG", "listenerNotified"); } }, 3000); } 

Ahora presione el botón b , luego presione el botón atrás y verá la salida en cuestión.

Might it be the reason of your app crash? Es difícil decirlo sin ver lo que tienes. Me gustaría tener en cuenta que cuando el new Handler() es instanciado en un hilo (el hilo principal en su caso), el Handler se asocia a la cola de mensajes del Looper del hilo, enviando y procesando mensajes Runnable y mensajes Desde la cola. Los mensajes Runnable y los mensajes tienen una referencia al Runnable destino. A pesar de que el método onDestroy() no es un "destructor", es decir, cuando el método devuelve la instancia de la Activity no se matará inmediatamente ( ver ), la memoria no puede ser GC-ed debido a la referencia implícita * A la Activity . Usted estará goteando hasta que el Runnable fuera de cola de la cola de mensajes del Looper y sea procesado.

Se puede encontrar una explicación más detallada sobre cómo filtrar un contexto: Handlers & Inner Classes


* Instancia de clase interna anónima Runnable tiene una referencia a una instancia de clase interna anónima View.OnClickListener que, a su vez, tiene una referencia a la instancia de Activity .

Es posible que tenga que considerar no sólo contabilizar retrasado ejecutar a manejador. Es posible que encuentre problemas cuando su tarea en ejecución en un hilo separado y su actividad ya está destruida. Usted puede hacer y poner en práctica de esta manera.

 your class activity { Handler mHandler; .. onCreate () { mHandler = new Handler(); } .. onDestory () { if (mHandler != null) { mHandler.removeCallbacksAndMessages(null); mHandler = null; } } private void post (Runnable r) { if (mHandler != null) { mHandler.post(r); } } } 

Con ello, cualquier tarea pendiente en la cola de mensajes del controlador se destruirá cuando se destruya la actividad.

Sólo para hacer que considere que usted es consciente de que usted no necesita ejecutar ninguna tarea después de la actividad se destruye.

La respuesta llega a ser "sí". Y esto puede causar Memory Leak por el camino.

  • Llamar stopSelf () en servicio mientras el subproceso está en ejecución
  • Utilizar Otto para actualizar un listadapter de un GcmListenerService
  • La mejor manera de ejecutar el método asincrónicamente en Android (compacto y correcto)
  • Aplicación android se estrella en el cambio de url de vista web
  • Android cómo ejecutarOnUiThread en otra clase?
  • ¿Qué pasa con multithreading en Android SQLite?
  • No recibe datos de ubicación del hilo
  • RxJava Multithreading con Realm - Acceso al dominio desde un subproceso incorrecto
  • Actualización y bloqueo de CountDownTimer
  • ¿Por qué los servicios de android se ejecutan en el hilo de la interfaz de usuario?
  • Uso de la concurrencia de Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.