Recreando una actividad

Hay algunos escenarios en los que tu actividad puede ser destruida debido al comportamiento normal de la aplicación, como cuando el usuario pulsa el botón Volver o tu actividad señala su propia destrucción llamando a finish(). También es posible que la destruya el sistema si se encuentra parada y no se ha utilizado en un tiempo o si la actividad en primer plano necesita más recursos y el sistema debe cerrar algunos procesos en segundo plano para recuperar memoria.

Cuando tu actividad se destruye porque el usuario presiona el botón Volver o la actividad se finaliza a sí misma, la información que tenía el sistema de dicha instancia de Activity se pierde para siempre porque se ha indicado que ya no se necesita la actividad. Sin embargo, si el sistema destruye la actividad debido a la falta de recursos (en lugar de por el comportamiento normal de la aplicación), entonces aunque la instancia de Activity se haya perdido, se recuerda que existía, de forma que si el usuario vuelve a ella, el sistema crea una nueva instancia de la actividad usando un conjunto de datos guardados que describen el estado en que se encontraba cuando se destruyó. Estos datos que guarda el sistema para recuperar el estado previo se conocen con el nombre de "estado de la instancia" y consiste en una colección de pares clave-valor almacenados en un objeto Bundle.

Precaución: Cada vez que el usuario rota la pantalla tu actividad se destruye y se vuelve a crear. Cuando la pantalla cambia de orientación, el sistema destruye y vuelve a crear la actividad en primer plano porque la configuración de pantalla ha cambiado y tu actividad puede necesitar cargar recursos alternativos (como los archivos de interfaz de usuario).

Por defecto, el sistema usa el Bundle de estado de instancia para guardar información acerca de cada objeto View de la interfaz de usuario de tu actividad (como el texto introducido en un objeto EditText). Así que, si la instancia de tu actividad se destruye y se vuelve a crear, el estado de la interfaz se restaura al estado previo sin necesidad de que escribas ni una línea de código. Sin embargo, puede que tu actividad tenga más información de estado que puedas querer restaurar, como variables miembro que sigan el progreso del usuario en la actividad.

Nota: Para que el sistema Android pueda restaurar el estado de las vistas de tu actividad, cada vista debe tener un ID único, provisto por el atributo android:id.

Para guardar datos adicionales sobre el estado de la actividad, debes sobreescribir el método de retrollamada onSaveInstanceState(). El sistema llama este método cuando el usuario está dejando tu actividad y le pasa el objeto Bundle que se guardará en caso de que tu actividad se destruya de forma inesperada. Si más tarde el sistema debe recrear la instancia de la actividad, le pasa el mismo objeto Bundle a los métodos onRestoreInstanceState() y onCreate().

Figura 2. Cuando el sistema empieza a parar tu actividad, llama a onSaveInstanceState() (1) donde puedes especificar datos de estado adicionales que te gustaría guardar en caso de que la instancia de Activity tenga que volver a crearse. Si se destruye la actividad y se debe recrear la misma instancia, el sistema pasa la información de estado definida en (1) a los métodos onCreate() (2) y onRestoreInstanceState() (3).

Guardar el estado de tu actividad


Cuando tu actividad empieza a pararse, el sistema llama a onSaveInstanceState() para que tu actividad pueda guardar la información de estado en una colección de pares clave-valor. La implementación por defecto de este método guarda información acerca del estado de la jerarquía de vistas de la actividad, como el texto en un control EditText o la posición de desplazamiento en un ListView.

Para guardar información de estado adicional para tu actividad, debes implementar onSaveInstanceState() y añadir pares clave-valor al objeto Bundle. Por ejemplo:

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Guardamos el estado actual del juego
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
    
    // Llamamos siempre a la superclase para que pueda guardar el estado
    // de la jerarquía de vistas
    super.onSaveInstanceState(savedInstanceState);
}

Precaución: Siempre hay que llamar a la implementación de onSaveInstanceState() de la superclase para que la implementación por defecto pueda guardar el estado de la jerarquía de vistas.

Restaurar el estado de la actividad


Cuando tu actividad se recrea después de haberse destruído previamente, puedes recuperar el estado guardado desde el Bundle que el sistema pasa a tu actividad. Tanto el método de retrollamada onCreate() como onRestoreInstanceState() reciben el mismo Bundle que contiene la información de estado de la instancia.

Dado que el método onCreate() se llama tanto si el sistema está creando una nueva instancia de tu actividad como si está recreando una previa, debes comprobar si el Bundle de estado es nulo antes de intentar leerlo. Si es nulo, entonces el sistema está creando una nueva instancia de la actividad, en lugar de restaurar una anterior que había sido destruída.

Por ejemplo, así es como recuperarías una cierta información de estado en onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Primero llamamos siempre a la superclase
   
    // Comprobamos si estamos recreando una instancia destruida previamente
    if (savedInstanceState != null) {
        // Restauramos el valor de los miembros del estado guardado
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Aquí probablemente inicializaríamos los miembros con valores por defecto
        // para una nueva instancia
    }
    ...
}

En lugar de restaurar el estado durante onCreate() puedes elegir implementar onRestoreInstanceState(), método que el sistema llama después del método onStart(). El sistema llama a onRestoreInstanceState() sólo si hay un estado guardado que restaurar, por lo que no necesitas comprobar si el Bundle es nulo:

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Siempre llamamos a la superclase para que pueda restaurar la jerarquía
    // de vistas
    super.onRestoreInstanceState(savedInstanceState);
   
    // Restaura los miembros de estado de la instancia guardada
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

Precaución: Siempre se debe llamar primero a la implementación de onRestoreInstanceState() de la superclase para que la implementación por defecto pueda restaurar el estado de la jerarquía de vistas.

Para aprender más sobre cómo recrear tu actividad debido a un evento de reinicio en tiempo de ejecución (como cuando se rota la pantalla), lee Manejando cambios en tiempo de ejecución.