Parando y reanudando una actividad

Esta lección te enseñará a

  1. Parar tu actividad
  2. Iniciar/Reiniciar tu actividad

También deberías leer

Parar y reanudar tu actividad de forma adecuada es un proceso importante en el ciclo de vida de la actividad que asegura que los usuarios tengan la impresión de que tu aplicación siempre responde y no pierde su progreso. Hay unos pocos escenarios clave en los que se para y reanuda tu actividad:

  • El usuario abre la ventana de Aplicaciones Recientes y lanza otra aplicación. La actividad que está en primer plano en tu aplicación en ese momento se para. Si el usuario vuelve a tu aplicación desde el icono del lanzador de la pantalla de Inicio, la actividad se reanuda.
  • El usuario lleva a cabo una acción en tu aplicación que inicia una nueva actividad. La actividad actual se para cuando se crea la segunda actividad. Si el usuario presiona entonces el botón Volver, se restaura la primera actividad.
  • El usuario recibe una llamada de teléfono mientras usa tu aplicación en su móvil.

La clase Activity proporciona dos métodos de ciclo de vida, onStop() y onRestart(), que permiten manejar específicamente cómo se parará y reanudará tu actividad. Al contrario que el estado de pausa, que identifica una obstrucción parcial de la interfaz de usuario, el estado de parada garantiza que la interfaz de usuario no es visible y que el foco del usuario se encuentra en otra actividad (o en otra aplicación totalmente distinta).

Nota: Dado que el sistema mantiene tu instancia de Activity en la memoria del sistema cuando esta se para, es posible que no necesites implementar onStop() y onRestart() (o incluso onStart()). Para la mayoría de las actividades que son relativamente simples, la actividad se parará y reanudará sin problemas y puede que sólo necesites usar onPause() para pausar las acciones que sigan en ejecución y desconectarte de los recursos del sistema.

Figura 1. Cuando el usuario deja tu actividad, el sistema llama a onStop() para parar la actividad (1). Si el usuario vuelve mientras la actividad se encuentra parada, el sistema llama a onRestart() (2), seguido rápidamente de onStart() (3) y onResume() (4). Observa que no importa el escenario que cause que la actividad se pare, el sistema siempre llama a onPause() antes de llamar a onStop().

Parar tu actividad


Cuando tu actividad recibe una llamada al método onStop(), ya no está visible y debería liberar casi todos los recursos que no necesite mientras el usuario no la está utilizando. Una vez que se para tu actividad, el sistema puede destruir la instancia si necesita recuperar memoria de sistema. En casos extremos, el sistema puede matar el proceso de tu aplicación sin ejecutar la retrollamada final onDestroy(), por lo que es importante que uses onStop() para liberar recursos que pudieran causar una fuga de memoria.

Aunque el método onPause() se llama antes de onStop(), deberías usar onStop() para llevar a cabo operaciones de cierre que lleven más tiempo y consuman más CPU, como guardar información en una base de datos.

Por ejemplo, a continuación se muestra una implementación de onStop() que guarda el contenido del borrador de una nota a almacenamiento persistente:

@Override
protected void onStop() {
    super.onStop();  // Siempre llamamos primero al método de la super clase

    // Guardamos el borrador actual de la nota, porque la actividad se está parando
    // y queremos asegurarnos de que el progreso en la nota actual no se pierda.
    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

    getContentResolver().update(
            mUri,    // La URI de la nota a actualizar.
            values,  // Correspondencia de nombres de columnas y valores a aplicar.
            null,    // No utilizamos ningún criterio SELECT.
            null     // No se utiliza ninguna columna de WHERE.
            );
}

Cuando se para tu actividad, el objeto Activity se mantiene residente en memoria y se le vuelve a llamar cuando se reanuda la actividad. No necesitas reinicializar componentes que se crearon en alguno de los métodos de retrollamada que llevan al estado de Reanudada. El sistema también lleva un registro del estado actual de cada View en la interfaz de usuario, por lo que si el usuario introdujo un texto en un control EditText, el contenido se mantiene para que no tengas que guardarlo y restaurarlo.

Nota: Incluso si el sistema destruye tu actividad mientras está parada, seguirá manteniendo el estado de los objetos View (como el texto en un EditText) en un Bundle (un blob de pares clave-valor) y los restaurará si el usuario vuelve a la misma instancia de la actividad (la siguiente lección trata en más profundidad el uso de Bundle para guardar otros datos de estado para el caso de que tu actividad sea destruida y se vuelva a crear).

Iniciar/Reiniciar tu actividad


Cuando tu actividad vuelve a primer plano desde el estado de parada, recibe una llamada a onRestart(). El sistema también llama al método onStart(), cosa que sucede cada vez que tu actividad pasa a ser visible (ya sea porque se está volviendo a crear o se está creando por primera vez). El método onRestart(), sin embargo, sólo se llama cuando la actividad se reanuda desde el estado de parada, por lo que puedes utilizarlo para lógica de restauración que sea necesaria sólo si la actividad fue parada anteriormente, pero no destruida.

Es poco común que una aplicación necesite utilizar onRestart() para restaurar el estado de la actividad, así que no hay ninguna línea de guía para este método que aplique a la gran mayoría de las aplicaciones. Sin embargo, dado que esencialmente el método onStop() debería limpiar todos los recursos de tu aplicación, necesitarás reinstanciarlos cuando la actividad reinicie. Aún así, también necesitas instanciarlos cuando tu actividad se crea por primera vez (cuando no existe una instancia de la actividad). Por esta razón, deberías usar el método de retrollamada onStart() como contrapartida del método onStop(), porque el sistema llama a onStart() tanto al crear la actividad como cuando se reinicia la actividad desde el estado de parada.

Por ejemplo, dado que el usuario puede haber estado un largo periodo de tiempo sin volver a tu aplicación, el método onStart() es un buen sitio para verificar si las características requeridas del sistema están habilitadas:

@Override
protected void onStart() {
    super.onStart();  // Siempre llamamos primero al método de la super clase
    
    // La actividad está siendo reiniciada o iniciada por primera vez por lo
    // que aquí es donde deberíamos asegurarnos de que el GPS está habilitado
    LocationManager locationManager = 
            (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    
    if (!gpsEnabled) {
        // Aquí crearíamos un diálogo pidiendo al usuario activar el GPS y usaríamos una
        // intención con la acción android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS
        // para llevar al usuario a la pantalla de Configuración para activar el GPS
    }
}

@Override
protected void onRestart() {
    super.onRestart();  // Siempre llamamos primero al método de la super clase
    
    // La actividad está siendo reiniciada desde el estado de parada   
}

Cuando el sistema destruye tu actividad, llama al método onDestroy() de tu instancia de Activity. Generalmente deberías haber liberado la mayor parte de tus recursos en onStop(), por lo que, cuando recibas una llamada a onDestroy(), en la mayor parte de las aplicaciones no quedará mucho por hacer. Este método es tu última oportunidad de limpiar recursos que pudieran llevar a una fuga de memoria, por lo que deberías asegurarte de que los hilos adicionales han sido destruidos y que otras acciones de larga duración como la traza de métodos también hayan parado.