Liberar recursos en onPause en lugar de onDestroy

Se trata de POST-nido de abeja (es decir, Android 3.0 +) y las citas a continuación vienen de https://developer.android.com/reference/android/app/Activity.html

Según el ciclo de vida, onStop y onDestroy son killable, esto significa:

Observe la columna "Killable" en la tabla anterior – para aquellos métodos que están marcados como killable, después de que el método devuelve el proceso que aloja la actividad puede ser destruido por el sistema en cualquier momento sin que se ejecute otra línea de su código

  1. En otras palabras, onStop (a lo largo de los otros que se producen antes de este evento) está garantizado para ser llamado, pero en el momento en que el método vuelve, el proceso podría morir, por lo que onDestroy no se garantiza que se llame.

    Otra cita dice:

    Para aquellos métodos que no están marcados como matables, el proceso de la actividad no será eliminado por el sistema a partir del momento en que se llama al método y continúa después de que regrese.

    Seguido por

    Por lo tanto, una actividad está en el estado eliminable , por ejemplo, entre después onPause () hasta el inicio de onResume ().

  2. Pero esto no corresponde a lo dicho anteriormente, a menos que esto sólo corresponda a PRE-panal . Esto no es cierto para POST-nido de abeja , ¿verdad? Así que, básicamente, tanto onPause y onStop están garantizados para ser llamado.

  3. Suponiendo que sólo libero un recurso en onDestroy, entonces esto podría conducir a una posible fuga ya que onDestroy podría no ser llamado, ¿verdad?

  4. Sin embargo, este escenario (es decir, onDestroy no se llama) ocurre además cuando el proceso es asesinado por el propio Android? ¿Existen otros escenarios que causen que onDestroy no se llame, por lo que se pierde el recurso .

  5. ¿Es cierto que cuando Android mata el proceso que los recursos serán destruidos y no se puede producir una fuga (incluso cuando no explícitamente lanzado el recurso?).

Sírvanse proporcionar información detallada sobre si esas afirmaciones (1) (2) (3) (4) (5) son correctas o no.

En primer lugar vamos a entender lo que está pasando con la documentación que citó.

Los siguientes comandos muestran la salida de git blame del archivo Activity.java en AOSP:

 $ cd $AOSP/frameworks/base $ git blame ./core/java/android/app/Activity.java 

La parte relevante de la salida:

 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 363) * <p>Note the "Killable" column in the above table -- for those methods that 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 364) * are marked as being killable, after that method returns the process hosting the 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 365) * activity may killed by the system <em>at any time</em> without another line 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 366) * of its code being executed. Because of this, you should use the 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 367) * {@link #onPause} method to write any persistent data (such as user edits) 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 368) * to storage. In addition, the method 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 369) * {@link #onSaveInstanceState(Bundle)} is called before placing the activity 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 370) * in such a background state, allowing you to save away any dynamic instance 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 371) * state in your activity into the given Bundle, to be later received in 550116576 (RoboErik 2014-07-09 15:05:53 -0700 372) * {@link #onCreate} if the activity needs to be re-created. 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 373) * See the <a href="#ProcessLifecycle">Process Lifecycle</a> 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 374) * section for more information on how the lifecycle of a process is tied 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 375) * to the activities it is hosting. Note that it is important to save 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 376) * persistent data in {@link #onPause} instead of {@link #onSaveInstanceState} 5c40f3fcc (Daisuke Miyakawa 2011-02-15 13:24:36 -0800 377) * because the latter is not part of the lifecycle callbacks, so will not 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 378) * be called in every situation as described in its documentation.</p> 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 379) * 0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 380) * <p class="note">Be aware that these semantics will change slightly between 0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 381) * applications targeting platforms starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB} 0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 382) * vs. those targeting prior platforms. Starting with Honeycomb, an application 0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 383) * is not in the killable state until its {@link #onStop} has returned. This 0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 384) * impacts when {@link #onSaveInstanceState(Bundle)} may be called (it may be 0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 385) * safely called after {@link #onPause()} and allows and application to safely 0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 386) * wait until {@link #onStop()} to save persistent state.</p> 0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 387) * 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 388) * <p>For those methods that are not marked as being killable, the activity's 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 389) * process will not be killed by the system starting from the time the method 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 390) * is called and continuing after it returns. Thus an activity is in the killable 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 391) * state, for example, between after <code>onPause()</code> to the start of 9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 392) * <code>onResume()</code>.</p> 

Tenga en cuenta que el párrafo que analiza el comportamiento después de Honeycomb fue añadido por Dianne Hackborn el 2010-12-07, mientras que los párrafos adjuntos datan de 2009-03-03.

Lo que nos dice es que Dianne agregó el nuevo párrafo sin actualizar el resto del javadoc, por lo tanto la contradicción. Desafortunadamente, esto no es raro en Android.

A sus preguntas:

1) En post-Honeycomb versiones de Android tanto onResume() y onStop() están garantizados para ser llamado (como se indica por Dianne Hackborn en su adición a la actividad javadoc).

2) En pre-Honeycomb sólo onPause() se garantiza que se llamará (como se indica en la versión anterior de la actividad de javadoc)

3,4,5) onDestroy() no se llamará sólo si el proceso que aloja toda la aplicación es eliminado. Cuando el proceso se destruye, todos los recursos asignados a él se liberan, por lo tanto, no hay riesgo de pérdida de memoria en este caso.

Nota importante : dado que la liberación de recursos en onDestroy() no causará pérdida de memoria, podría parecer una buena idea poner todo el código de "liberación" allí. Sin embargo, rara vez es el enfoque óptimo. ¿Por qué? Lee abajo.

Cuando la Activity pasa al fondo se detiene, pero no se destruye (normalmente). Activity puede permanecer en este estado "detenido" durante bastante tiempo, y se iniciará de nuevo si el usuario vuelve a la aplicación. Si libera recursos en onDestroy() , que no se llama de forma predeterminada cuando la Activity pasa al fondo, la Activity se mantendrá en estos recursos mientras está en estado detenido, lo que provocará una mayor cantidad de recursos consumidos por la aplicación en el estado de fondo.

Cuando Android se queda sin memoria, comienza a matar los procesos para liberar la memoria consumida por ellos. Una de las consideraciones más importantes tomadas en cuenta al elegir qué procesos matar es su consumo de recursos. Por lo tanto, si su aplicación se mantiene a los recursos en estado de fondo detenido, tendrá una mayor probabilidad de ser asesinado por Android.

Además, nosotros, los desarrolladores, debemos asegurarnos de que hacemos las mejores aplicaciones para nuestros usuarios. La aplicación que consume una cantidad no mínima de recursos del teléfono del usuario y de la batería mientras está en segundo plano no es una buena aplicación. ¡Y los usuarios lo sabrán!

Por lo tanto, onStop() fuertemente la liberación de todos los recursos en el método onStop() . Normalmente no sobrescribo métodos onDestroy() en Activities y Fragments en absoluto.

Corolario: Como señalado por @Juan en su comentario, la importante nota anterior tiene un corolario igualmente importante, pero no tan evidente: onStart() debería ser el único método en el que se asignan los recursos. Sea cual sea su definición de "recursos", ni onCreate() ni onResume() deben asignar estos recursos.

Creo que Vasily proporcionó una gran respuesta. Todavía hay un punto pequeño pero importante que falta allí relacionado con

  1. ¿Es cierto que cuando Android mata el proceso que los recursos serán destruidos y no se puede producir una fuga (incluso cuando no explícitamente lanzado el recurso?).

La respuesta depende de qué es exactamente lo que usted tiene miedo. Como Vasily señaló Android (que se basa en Linux) es un sistema operativo seguro moderno que garantiza que cuando el proceso es asesinado, toda la memoria será liberada, además todos los archivos abiertos, conexiones de red, etc también se cerrarán correctamente. Así que no habrá fugas de recursos en el sentido usual.

Todavía hay un escenario potencialmente problemático. Supongamos que tiene alguna lógica que realiza cuando libera algún recurso, es decir, algo que pondría en un destructor en C ++ o en una implementación de Closeable.close en Java. Por ejemplo, tiene un caché en la memoria que retrasa escribe en un archivo con batching. Normalmente descarga la caché en memoria en onDestroy y todo funciona bien. Pero cuando el proceso es forzado por Android, onDestroy puede no ser llamado y su lógica de descarga no se ejecuta y por lo tanto puede perder algunos datos y / o tener un estado no válido en su almacenamiento persistente. Así que si tienes algo como esto, debes asegurar la consistencia realizando esa lógica en un lugar más confiable: onPause o onStop .

  • Ciclo de vida del fragmento AppCompat cambiado
  • La aplicación reanuda los resultados en bloqueo con FormsAppCompatActivity
  • Diferencia principal entre el Manifiesto y el Registro Programático de BroadcastReceiver
  • Android: onPostResume se llama después de que se reanude el fragmento
  • Actividad ciclo de vida: ¿Por qué se establece en "Pausado" y no "Detenido"
  • Vista de Android - onAttachedToWindow y onDetachedFromWindow - cuándo se llaman en el ciclo de vida de la actividad?
  • Ciclo de vida del fragmento con respecto a su actividad
  • Diferencia entre onPause y onStop ()
  • Fragmento de Android superpuesto por otro fragmento todavía se muestra y no onPause
  • El servicio de Android con START_STICKY se bloquea al eliminar la aplicación
  • Fragmento no invoca onSaveInstanceState al pasar ViewPager?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.