¿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()
.
- WebViewClient shouldInterceptRequest Congela el WebView
- Android claro hilo webview, libre de memoria, evitar OutOfMemoryError
- Android: los hilos no se ejecutan en paralelo
- Quiero crear thread temporizador para Android con Xamarin
- ¿Cuándo usar un hilo o servicio en Android?
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.
- ¿Se puede usar la fila de respaldo de archivo Square Tape en el hilo principal de android?
- ProgressDialog animaciones pausas en grandes setText ()
- Thread.join con un patrón de "reintento"
- SQLite database, multithreading, bloqueos y sincronización de cuentas en android
- Cancelar ProgressDialog y detener el hilo
- Cargando imagen de forma sincrónica con Glide
- Método de servicio de Android llamado en hilo diferente. ¿Sigue funcionando en el hilo principal?
- ¿Cómo hago la aplicación de Android que hace algo cada X segundo
¿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.
- ¿Qué es carotene_o4t y por qué causa problemas con la compilación de un programa utilizando opencv con Qt en Android?
- ConstraintLayout versión estable?