Skip to content

Most visited

Recently visited

navigation

Manejo de cambios en tiempo de ejecución

Algunas configuraciones de dispositivos pueden cambiar durante el tiempo de ejecución (por ejemplo, la orientación de la pantalla, la disponibilidad del teclado y el idioma). Cuando se producen estos cambios, Android reinicia la Activity en ejecución (se llama a onDestroy() y luego a onCreate()). El comportamiento de reinicio está diseñado para ayudar a tu aplicación a adaptarse a las configuraciones nuevas al recargar automáticamente tu aplicación con recursos alternativos que coinciden con la nueva configuración del dispositivo.

Para manejar correctamente un reinicio, es importante que tu actividad restaure su estado anterior mediante el ciclo de vida normal de la actividad , en el cual Android llama a onSaveInstanceState() antes de destruir tu actividad para que puedas guardar datos sobre el estado de la aplicación. Luego, puedes restaurar el estado durante onCreate() o onRestoreInstanceState().

Para comprobar si tu aplicación se reinicia con el estado de la aplicación intacto, debes invocar cambios de configuración (por ejemplo, cambiar la orientación de la pantalla) mientras realizas diversas tareas en tu aplicación. Tu aplicación debe ser capaz de reiniciarse en cualquier momento sin perder datos del usuario o el estado para poder manejar eventos tales como cambios de configuración, o cuando el usuario recibe una llamada de teléfono entrante y luego vuelve a tu aplicación mucho después de que el proceso de tu aplicación quizá se haya destruido. Para aprender cómo restaurar el estado de tu actividad, lee acerca del ciclo de vida de la actividad.

Sin embargo, quizá exista una situación en la que reiniciar tu aplicación y restaurar grandes cantidades de datos pueda ser costoso y crear una experiencia deficiente para el usuario. En dicha situación, tienes otras dos opciones:

  1. Retener un objeto durante un cambio de configuración

    Permite que tu actividad se reinicie cuando una configuración cambia, pero lleva un objeto con estado a la nueva instancia de tu actividad.

  2. Manejar el cambio de configuración tú mismo

    Evita que el sistema reinicie tu actividad durante ciertos cambios de configuración, pero recibe un callback cuando las configuraciones cambian, de modo que puedas actualizar manualmente tu actividad según sea necesario.

Retención de un objeto durante un cambio de configuración

Si para reiniciar tu actividad se deben recuperar grandes conjuntos de datos, restablecer una conexión de red o realizar otras operaciones intensivas, un reinicio completo debido a un cambio de configuración podría dar como resultado una experiencia lenta para el usuario. Además, quizá no pueda restaurar completamente el estado de actividad con el Bundle que el sistema guarda con el callback onSaveInstanceState(); no está diseñada para transferir objetos grandes (como mapas de bits) y los datos que contiene deben serializarse y, luego, deserializarse, lo que puede consumir mucha memoria y hacer que el cambio de configuración sea lento. En dicha situación, puedes reducir la carga que supone reiniciar tu actividad reteniendo un Fragment cuando la actividad se reinicie debido a un cambio de configuración. Este fragmento puede contener referencias a los objetos con estado que deseas retener.

Cuando el sistema Android cierra tu actividad debido a un cambio de configuración, los fragmentos de tu actividad que ha marcado para retener no se destruyen. Puedes agregar tales fragmentos a tu actividad para preservar los objetos con estado.

Para retener objetos con estado en un fragmento durante un cambio de configuración en tiempo de ejecución:

  1. Extiende la clase Fragment y declara referencias a tus objetos con estado.
  2. Llama a setRetainInstance(boolean) cuando se crea el fragmento.
  3. Agrega el fragmento a tu actividad.
  4. Usa FragmentManager para recuperar el fragmento cuando se reinicia la actividad.

Por ejemplo, define tu fragmento de la siguiente forma:

public class RetainedFragment extends Fragment {

    // data object we want to retain
    private MyDataObject data;

    // this method is only called once for this fragment
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // retain this fragment
        setRetainInstance(true);
    }

    public void setData(MyDataObject data) {
        this.data = data;
    }

    public MyDataObject getData() {
        return data;
    }
}

Advertencia: Si bien puedes almacenar cualquier objeto, nunca debes pasar un objeto que esté vinculado con la Activity, por ejemplo, un Drawable, un Adapter, una View u otros objetos asociados con un Context. Si lo haces, perderás todas las vistas y los recursos de la instancia de actividad original. (Pérdida de recursos significa que tu aplicación retiene los recursos y no se los puede recolectar como elementos no utilizados, por lo que se puede perder mucha memoria).

Luego, usa FragmentManager para agregar el fragmento a la actividad. Puedes obtener el objeto de datos del fragmento cuando la actividad comience nuevamente durante los cambios de configuración en tiempo de ejecución. Por ejemplo, define tu actividad de la siguiente forma:

public class MyActivity extends Activity {

    private RetainedFragment dataFragment;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // find the retained fragment on activity restarts
        FragmentManager fm = getFragmentManager();
        dataFragment = (DataFragment) fm.findFragmentByTag(“data”);

        // create the fragment and data the first time
        if (dataFragment == null) {
            // add the fragment
            dataFragment = new DataFragment();
            fm.beginTransaction().add(dataFragment, “data”).commit();
            // load the data from the web
            dataFragment.setData(loadMyData());
        }

        // the data is available in dataFragment.getData()
        ...
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // store the data in the fragment
        dataFragment.setData(collectMyLoadedData());
    }
}

En este ejemplo, onCreate() agrega un fragmento o restaura una referencia a dicho fragmento. onCreate() también almacena el objeto con estado dentro de la instancia del fragmento. onDestroy() actualiza el objeto con estado dentro de la instancia del fragmento retenido.

Maneja el cambio de configuración tú mismo

Si tu aplicación no necesita actualizar recursos durante un cambio de configuración específico y tienes una limitación de rendimiento que le exige que evite el reinicio de la actividad, puedes declarar que tu actividad maneja el cambio de configuración por sí misma, lo que evita que el sistema reinicie tu actividad.

Nota: Al manejar el cambio de configuración tú mismo, puede resultar mucho más difícil utilizar recursos alternativos, ya que el sistema no los aplica automáticamente . Esta técnica debe considerarse como último recurso cuando debes evitar los reinicios debido a un cambio de configuración, y no se recomienda para la mayoría de las aplicaciones.

Para declarar que tu actividad maneja un cambio de configuración, edita el elemento <activity> correspondiente en el archivo de manifiesto para incluir el atributo android:configChanges con un valor que represente la configuración que deseas manejar. Los posibles valores se enumeran en la documentación del atributo android:configChanges (los valores más usados son "orientation" para evitar reinicios cuando cambia la orientación de la pantalla y "keyboardHidden" para evitar reinicios cuando cambia la disponibilidad del teclado). Puedes declarar varios valores de configuración en el atributo separándolos con una barra vertical |.

Por ejemplo, el código de manifiesto siguiente declara una actividad que maneja tanto el cambio de orientación de la pantalla como el cambio de disponibilidad del teclado:

<activity android:name=".MyActivity"
          android:configChanges="orientation|keyboardHidden"
          android:label="@string/app_name">

Cuando una de estas configuraciones cambia, MyActivity no se reinicia. En cambio, MyActivity recibe una llamada a onConfigurationChanged(). A este método se le pasa un objeto Configuration que especifica la nueva configuración del dispositivo. Al leer los campos de la Configuration, puedes determinar la nueva configuración y realizar los cambios correspondientes actualizando los recursos utilizados en tu interfaz. Cuando se llama a este método, el objeto Resources de tu actividad se actualiza para devolver recursos sobre la base de la nueva configuración, de modo que puedas restablecer fácilmente elementos de tu IU sin que el sistema reinicie tu actividad.

Advertencia: A partir de Android 3.2 (el nivel de API 13), el “tamaño de pantalla” también cambia cuando el dispositivo cambia entre la orientación vertical y horizontal. Por lo tanto, si deseas evitar los reinicios en tiempo de ejecución debido al cambio de orientación cuando desarrollas para el nivel de API 13 o niveles superiores (según se declara en los atributos minSdkVersion y targetSdkVersion ), debes incluir el valor "screenSize" además del valor "orientation". Es decir, debes declarar android:configChanges="orientation|screenSize". Sin embargo, si tu aplicación tiene como destino el nivel de API 12 o niveles superiores, tu actividad siempre maneja este cambio de configuración por sí misma (este cambio de configuración no reinicia tu actividad, ni siquiera cuando se ejecuta en un dispositivo Android 3.2 o superior).

Por ejemplo, en la siguiente implementación onConfigurationChanged() comprueba la orientación actual del dispositivo:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}

El objetoConfiguration representa todas las configuraciones actuales, no solo las que han cambiado. La mayoría de las veces, no le importará la forma exacta en la que ha cambiado la configuración, y podrá simplemente reasignar todos los recursos que proporcionan alternativas a la configuración que estás manejando. Por ejemplo, dado que el objeto Resources ahora está actualizado, puedes restablecer cualquier ImageView con setImageResource() y se usa el recurso correspondiente para la nueva configuración (como se describe en Provisión de recursos).

Ten en cuenta que los valores de los campos Configuration son enteros y coinciden con constantes específicas de la clase Configuration. Para hallar documentación sobre las constantes que deben usarse con cada campo, consulta el campo correspondiente en la referencia Configuration.

Recuerda: Cuando declaras que tu actividad maneja un cambio de configuración, eres responsable de restablecer los elementos para los cuales proporcionas alternativas. Si declaras que tu actividad maneja el cambio de orientación y tiene imágenes que deben pasar de la orientación horizontal a la vertical, debes reasignar cada recurso a cada elemento durante onConfigurationChanged().

Si no necesitas actualizar tu aplicación según estos cambios de configuración, como alternativa puedes optar por no implementar onConfigurationChanged(). En este caso, todos los recursos utilizados antes del cambio de configuración se siguen utilizando , y tú solamente evitaste el reinicio de tu actividad. Sin embargo, tu aplicación siempre debe ser capaz de cerrarse y reiniciarse con su estado anterior intacto, por lo que no debes considerar esta técnica como un escape de la retención de su estado durante el ciclo de vida normal de la actividad. No solo porque existen otros cambios de configuración que no puedes evitar que reinicien tu aplicación, sino también porque debes manejar ciertos eventos, por ejemplo, cuando el usuario abandona tu aplicación y esta se destruye antes de que el usuario vuelva a ella.

Para obtener más información sobre los cambios de configuración que puedes manejar en tu actividad, consulta la documentación de android:configChanges y la clase Configuration.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)