Está en la página 1de 21

GUÍA OFICIAL DE

ANDROID
Curso Udemy
Introducción a las actividades
La clase Activity es un componente clave de una app para Android, y la forma en que se inician y se crean las
actividades es una parte fundamental del modelo de aplicación de la plataforma. A diferencia de los
paradigmas de programación en los que las apps se inician con un método main(), el sistema Android inicia el
código en una instancia de Activity invocando métodos de devolución de llamada específicos que
corresponden a etapas específicas de su ciclo de vida.

En este documento, se introduce el concepto de actividades y se proporciona una guía simple sobre cómo
trabajar con ellas. A fin de obtener información adicional sobre las prácticas recomendadas para diseñar la
arquitectura de tu app, consulta la Guía de arquitectura de apps.

El concepto de actividades
La experiencia con la app para dispositivos móviles difiere de la versión de escritorio, ya que la interacción del
usuario con la app no siempre comienza en el mismo lugar. En este caso, no hay un lugar específico desde
donde el usuario comienza su actividad. Por ejemplo, si abres una app de correo electrónico desde la pantalla
principal, es posible que veas una lista de correos electrónicos. Por el contrario, si usas una app de redes
sociales que luego inicia tu app de correo electrónico, es posible que accedas directamente a la pantalla de la
app de correo electrónico para redactar uno.

La clase Activity está diseñada para facilitar este paradigma. Cuando una app invoca a otra, la app que realiza
la llamada invoca una actividad en la otra, en lugar de a la app en sí. De esta manera, la actividad sirve como el
punto de entrada para la interacción de una app con el usuario. Implementas una actividad como una subclase
de la clase Activity.

Una actividad proporciona la ventana en la que la app dibuja su IU. Por lo general, esta ventana llena la
pantalla, pero puede ser más pequeña y flotar sobre otras ventanas. Generalmente, una actividad implementa
una pantalla en una app. Por ejemplo, una actividad de una app puede implementar una pantalla Preferencias
mientras otra implementa una pantalla Seleccionar foto.

La mayoría de las apps contienen varias pantallas, lo cual significa que incluyen varias actividades. Por lo
general, una actividad en una app se especifica como la actividad principal, que es la primera pantalla que
aparece cuando el usuario inicia la app. Luego, cada actividad puede iniciar otra actividad a fin de realizar
diferentes acciones. Por ejemplo, la actividad principal de una app de correo electrónico simple podría
proporcionar una pantalla en la que se muestra una casilla de correo electrónico. A partir de aquí, la actividad
principal podría iniciar otras actividades que proporcionan pantallas para tareas como redactar correos y abrir
correos electrónicos individuales.

Si bien las actividades trabajan en conjunto a fin de crear una experiencia del usuario coherente en una app,
cada actividad se relaciona vagamente con otras actividades; por lo general, hay una pequeña cantidad de
dependencias entre las actividades de una app. De hecho, estas suelen iniciar actividades que pertenecen a
otras apps. Por ejemplo, una app de navegador podría iniciar la acción de "Compartir actividad" de una app de
redes sociales.
Si quieres usar actividades en tu app, debes registrar información sobre estas en el manifiesto de la app y
administrar los ciclos de vida de las actividades de manera apropiada. En el resto de este documento, se
presentan estos temas.

Cómo configurar el manifiesto


Para que tu app pueda usar actividades, debes declararlas, y también declarar algunos de sus atributos, en el
manifiesto.

Cómo declarar actividades

Para declarar tu actividad, abre tu archivo de manifiesto y agrega el elemento <activity> como objeto
secundario del elemento <application>. Por ejemplo:

    <manifest ... >


      <application ... >
          <activity android:name=".ExampleActivity" />
          ...
      </application ... >
      ...
    </manifest >
   

El único atributo obligatorio para este elemento es android:name, que especifica el nombre de la clase de la
actividad. También puedes agregar atributos que definan las características de la actividad, como una
etiqueta, un ícono o un tema de IU. Para obtener más información sobre estos y otros atributos, consulta la
documentación de referencia sobre el elemento <activity>.

Nota: Una vez que publiques tu app, no deberías cambiar los nombres de las actividades. Si lo haces, se
pueden romper algunas funcionalidades, como los accesos directos a las apps. Para obtener más información
sobre los cambios que debes evitar luego de la publicación, consulta Elementos que no debes modificar.

Cómo declarar filtros de intents

Los filtros de intents son una función muy útil de la plataforma de Android. Estos proporcionan la capacidad
de iniciar una actividad no solo en función de una solicitud explícita, sino también de una implícita. Por
ejemplo, una solicitud explícita podría indicar al sistema que debe "Iniciar la actividad 'Enviar correo
electrónico' en la app de Gmail". En cambio, una solicitud implícita le indica al sistema que debe "Iniciar una
pantalla 'Enviar correo electrónico' en cualquier actividad que pueda realizar la tarea". Cuando la IU del
sistema le pregunta al usuario qué app debe usar para realizar la tarea, ese es un ejemplo de un filtro de
intent.

Para aprovechar esta función, declara un atributo <intent-filter> en el elemento <activity>. La definición de
este elemento incluye un elemento <action> y, de manera opcional, un elemento <category> o <data>. Estos
elementos se combinan para especificar el tipo de intent al que puede responder la actividad. Por ejemplo, en
el siguiente fragmento de código, se muestra cómo configurar una actividad que envía datos de texto y recibe
solicitudes de otras actividades para hacerlo:

    <activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">


        <intent-filter>
            <action android:name="android.intent.action.SEND" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
    </activity>
   

En este ejemplo, el elemento <action> especifica que esta actividad envía datos. La declaración del elemento
<category> como DEFAULT permite a la actividad recibir solicitudes de inicio. El elemento <data> especifica el
tipo de datos que puede enviar esta actividad. En el siguiente fragmento de código, se muestra cómo llamar a
la actividad que se describe más arriba:

Java
    // Create the text message with a string
    Intent sendIntent = new Intent();
    sendIntent.setAction(Intent.ACTION_SEND);
    sendIntent.setType("text/plain");
    sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
    // Start the activity
    startActivity(sendIntent);
   
Si deseas que tu app sea independiente y que no permita que otras apps inicien sus actividades, no necesitas
filtros de intents adicionales. Las actividades que no quieras que estén disponibles para otras aplicaciones no
deben incluir filtros de intents, y puedes iniciarlas por medio de intents explícitos. Para obtener más
información sobre cómo tus actividades pueden responder a los intents, consulta Intents y filtros de intents.

Cómo declarar permisos

Puedes usar la etiqueta <activity> del manifiesto para controlar qué apps pueden iniciar una actividad en
particular. Una actividad superior no puede iniciar una actividad secundaria, a menos que ambas tengan los
mismos permisos en su manifiesto. Si declaras un elemento <uses-permission> para una actividad principal, cada
actividad secundaria debe tener un elemento <uses-permission>.

Por ejemplo, si tu app quiere usar una app hipotética llamada SocialApp para compartir una publicación en las
redes sociales, SocialApp debe definir el mismo permiso que la app que la llama debe tener:

    <manifest>
    <activity android:name="...."
       android:permission=”com.google.socialapp.permission.SHARE_POST”

    />
   

Luego, para poder llamar a SocialApp, tu app debe tener el mismo permiso que se estableció en el manifiesto
de SocialApp.

    <manifest>
       <uses-permission android:name="com.google.socialapp.permission.SHARE_POST" />
    </manifest>
   

Para obtener más información sobre los permisos y la seguridad en general, consulta Seguridad y permisos.

Cómo administrar el ciclo de vida de la actividad


A lo largo de su vida útil, una actividad pasa por varios estados. Para administrar las transiciones entre
estados, debes usar una serie de devoluciones de llamadas. En las siguientes secciones, se presentan estas
devoluciones de llamadas.

onCreate()

Debes implementar esta devolución de llamada, que se activa cuando el sistema crea tu actividad. Tu
implementación debe inicializar los componentes esenciales de tu actividad. Por ejemplo, tu app debería crear
vistas y vincular datos a listas aquí. Principalmente, este es el momento en el que debes llamar a
setContentView() para definir el diseño de la interfaz de usuario de tu actividad.

Cuando onCreate() finaliza, la siguiente devolución de llamada siempre es onStart().

onStart()

Cuando se cierra onCreate(), la actividad pasa al estado Iniciada y se vuelve visible para el usuario. Esta
devolución de llamada contiene los preparativos finales de la actividad para pasar al primer plano y
convertirse en interactiva.

onResume()

El sistema invoca esta devolución de llamada justo antes de que la actividad comience a interactuar con el
usuario. En este punto, la actividad es la primera de la pila de actividades y captura todo lo que el usuario
ingresa. La mayor parte de la funcionalidad principal de una app se implementa en el método onResume().

La devolución de llamada onPause() siempre va después de onResume().

onPause()

El sistema llama a onPause() cuando la actividad pierde el foco y pasa al estado Detenida. Este estado se
produce, por ejemplo, cuando el usuario presiona el botón Atrás o Recientes. Cuando el sistema llama a
onPause() para tu actividad, significa que esta aún está parcialmente visible, pero, a menudo, indica que el
usuario está saliendo de la actividad y que esta pronto pasará al estado Detenida o Reanudada.

Una actividad en estado Detenida puede continuar con la actualización de la IU si el usuario espera que esta
acción ocurra. Entre los ejemplos de tal actividad, se incluye mostrar una pantalla de mapa de navegación o la
reproducción de un reproductor multimedia. Incluso si estas actividades pierden el foco, el usuario espera que
su IU continúe actualizándose.

No debes usar onPause() para guardar datos de la aplicación o del usuario, realizar llamadas de red o ejecutar
transacciones de base de datos. Para obtener más información sobre cómo guardar datos, consulta Cómo
guardar y restablecer el estado de la actividad.

Una vez que finalice la ejecución de onPause(), la siguiente devolución de llamada será onStop() o
onResume(), dependiendo de lo que ocurra cuando la actividad pase al estado Detenida.

onStop()
El sistema llama a onStop() cuando la actividad ya no es visible para el usuario, lo cual puede ocurrir porque se
está eliminando la actividad, porque se inicia una nueva o porque una ya existente pasa al estado Reanudada y
cubre la actividad que se detuvo. En todos estos casos, la actividad detenida ya no está visible en absoluto.

La siguiente devolución de llamada que el sistema invoca puede ser onRestart() (si la actividad vuelve a
interactuar con el usuario) o onDestroy() (si esta actividad finaliza por completo).

onRestart()

El sistema invoca esta devolución de llamada cuando una actividad en estado Detenida está por volver a
iniciarse. onRestart() restaura el estado de la actividad desde el momento en que esta se detuvo.

Luego de esta devolución de llamada, siempre sigue onStart().

onDestroy()

El sistema invoca esta devolución de llamada antes de que se elimine una actividad.

Esta devolución de llamada es la última que recibe la actividad. onDestroy() suele implementarse a fin de
garantizar que todos los recursos de una actividad se liberen cuando esta, o el proceso que la contiene, se
elimina.

En esta sección, solo se proporciona una introducción a este tema. Para obtener un análisis más detallado del
ciclo de vida de la actividad y sus devoluciones de llamadas, consulta El ciclo de vida de la actividad.

Cómo interpretar el ciclo de vida de una actividad


Cuando un usuario navega por tu app, las instancias de Activity atraviesan diferentes estados de su ciclo de
vida. La clase Activity proporciona una serie de devoluciones de llamada que permiten a la actividad saber que
cambió un estado, es decir, que el sistema está creando, deteniendo o reanudando una actividad, o bien
finalizando el proceso en el que se encuentra.

Dentro de los métodos de devolución de llamada de un ciclo de vida, puedes declarar el comportamiento que
tendrá tu actividad cuando el usuario la abandone y la reanude. Por ejemplo, si creas un reproductor de video,
puedes pausar el video y cancelar la conexión de red cuando el usuario cambie a otra app. Cuando el usuario
regrese, podrás volver a establecer la conexión con la red y permitir que reanude el video desde el mismo
punto. En otras palabras, cada devolución de llamada te permite realizar un trabajo específico que es
apropiado para un cambio de estado en particular. Hacer el trabajo preciso en el momento adecuado y
administrar las transiciones correctamente hace que tu app sea más sólida y eficiente. Por ejemplo, una buena
implementación de las devoluciones de llamada de un ciclo de vida puede ayudar a garantizar que tu app:

 No falle si el usuario recibe una llamada telefónica o cambia a otra app mientras usa la tuya.
 No consuma recursos valiosos del sistema cuando el usuario no la use de forma activa.
 No pierda el progreso del usuario si este abandona tu app y regresa a ella posteriormente.
 No falle ni pierda el progreso del usuario cuando se gire la pantalla entre la orientación horizontal y la vertical.
En este documento, se explica en detalle el ciclo de vida de las actividades. El documento comienza
describiendo el paradigma del ciclo de vida. A continuación, se explica cada una de las devoluciones de
llamada: qué sucede internamente mientras se ejecutan y qué se debe implementar durante ellas. Luego,
introduce de forma breve la relación entre el estado de una actividad y la vulnerabilidad de un proceso que el
sistema está por finalizar. Por último, se abordan varios temas relacionados con las transiciones entre los
estados de una actividad.

Para obtener información sobre cómo administrar ciclos de vida, incluida orientación sobre prácticas
recomendadas, consulta Cómo administrar ciclos de vida con componentes que los priorizan y Cómo guardar
estados de IU. Para aprender a diseñar una app sólida y de calidad utilizando actividades junto con
componentes de arquitectura, consulta la Guía sobre la arquitectura de apps.

Conceptos de los ciclos de vida de las actividades


Para navegar por las transiciones entre las etapas del ciclo de vida de una actividad, la clase Activity
proporciona un conjunto básico de seis devoluciones de llamadas: onCreate(), onStart(), onResume(),
onPause(), onStop() y onDestroy(). El sistema invoca cada una de estas devoluciones de llamada cuando una
operación entra en un nuevo estado.

En la figura 1, se muestra una representación visual de este paradigma.


Figura 1: Ilustración simplificada del ciclo de vida de una actividad

Cuando el usuario comienza a abandonar la actividad, el sistema llama a métodos para desmantelarla. En
algunos casos, este desmantelamiento es solo parcial; la actividad todavía reside en la memoria (por ejemplo,
cuando el usuario cambia a otra app) y aún puede volver al primer plano. Si el usuario regresa a esa actividad,
se reanuda desde donde el usuario la dejó. Con algunas excepciones, se restringe a las apps para que no
inicien actividades cuando se ejecutan en segundo plano.

La probabilidad de que el sistema finalice un proceso determinado, junto con las actividades que contiene,
depende del estado de la actividad en ese momento. En Estado de la actividad y expulsión de la memoria,
obtendrás más información sobre la relación entre el estado y la vulnerabilidad a la expulsión.

Según la complejidad de tu actividad, probablemente no necesites implementar todos los métodos de ciclo de
vida. Sin embargo, es importante que comprendas cada uno de ellos y que implementes aquellos que
garanticen que tu app se comporte como esperan los usuarios.

En la siguiente sección de este documento, se proporcionan detalles sobre las devoluciones de llamada que
utilizas para administrar las transiciones entre estados.

Devoluciones de llamada del ciclo de vida


En esta sección, se brinda información conceptual y de implementación sobre los métodos de devolución de
llamada utilizados durante el ciclo de vida de una actividad.

Algunas acciones, como llamar a setContentView(), pertenecen a los propios métodos del ciclo de vida de la
actividad. Sin embargo, el código que implementa las acciones de un componente dependiente debe
colocarse en el propio componente. Para ello, debes hacer que el componente dependiente priorice el ciclo de
vida. Consulta Cómo administrar ciclos de vida con componentes que los priorizan para obtener más
información sobre cómo hacer que los componentes de tus dependencias prioricen los ciclos de vida.

onCreate()

Debes implementar esta devolución de llamada, que se activa cuando el sistema crea la actividad por primera
vez. Cuando se crea la actividad, esta entra en el estado Created. En el método onCreate(), ejecutas la lógica
de arranque básica de la aplicación que debe ocurrir una sola vez en toda la vida de la actividad. Por ejemplo,
tu implementación de onCreate() podría vincular datos a listas, asociar la actividad con un ViewModel y crear
instancias de algunas variables de alcance de clase. Este método recibe el parámetro savedInstanceState, que es
un objeto Bundle que contiene el estado ya guardado de la actividad. Si la actividad nunca ha existido, el valor
del objeto Bundle es nulo.

Si tienes un componente que prioriza el ciclo de vida y que está conectado al ciclo de vida de tu actividad,
recibirá el evento ON_CREATE. Se llamará al método anotado con @OnLifecycleEvent para que tu componente
que prioriza el ciclo de vida pueda realizar cualquier código de configuración que necesite para el estado de
creación.

El siguiente ejemplo del método onCreate() muestra la configuración básica de la actividad, como declarar la
interfaz de usuario (definida en un archivo XML de diseño), definir las variables de miembro y configurar parte
de la IU. En este ejemplo, se especifica el archivo de diseño XML haciendo pasar el ID de recurso del archivo
R.layout.main_activity a setContentView().
Java
TextView textView;

// some transient state for the activity instance


String gameState;

@Override
public void onCreate(Bundle savedInstanceState) {
    // call the super class onCreate to complete the creation of activity like
    // the view hierarchy
    super.onCreate(savedInstanceState);

    // recovering the instance state


    if (savedInstanceState != null) {
        gameState = savedInstanceState.getString(GAME_STATE_KEY);
    }

    // set the user interface layout for this activity


    // the layout file is defined in the project res/layout/main_activity.xml file
    setContentView(R.layout.main_activity);

    // initialize member TextView so we can manipulate it later


    textView = (TextView) findViewById(R.id.text_view);
}

// This callback is called only when there is a saved instance that is previously saved by using
// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore
// other state here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    textView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}

// invoked when the activity may be temporarily destroyed, save the instance state here
@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putString(GAME_STATE_KEY, gameState);
    outState.putString(TEXT_VIEW_KEY, textView.getText());

    // call superclass to save any view hierarchy


    super.onSaveInstanceState(outState);
}

Como alternativa a definir el archivo XML y pasarlo a setContentView(), puedes crear nuevos objetos View en
el código de tu actividad y crear una jerarquía de vistas insertando nuevos objetos View en un ViewGroup. A
continuación, utiliza esta disposición pasando la raíz ViewGroup a setContentView(). Para obtener más
información acerca de cómo crear una interfaz de usuario, consulta la documentación de Interfaz de usuario.

Tu actividad no reside en el estado Created. Después de que se termina de ejecutar el método onCreate(), la
actividad entra en el estado Started, y el sistema llama rápidamente a los métodos onStart() y onResume(). En
la siguiente sección, se explica la devolución de llamada onStart().

onStart()
Cuando la actividad entra en el estado Started, el sistema invoca esta devolución de llamada. La llamada
onStart() hace que el usuario pueda ver la actividad, mientras la app se prepara para que esta entre en primer
plano y se convierta en interactiva. Por ejemplo, este método es donde la app inicializa el código que
mantiene la IU.

Cuando la actividad pase al estado Started, cualquier componente que priorice el ciclo de vida vinculado al de
la actividad recibirá el evento ON_START.

El método onStart() se completa muy rápido y, al igual que con el estado Created, la actividad no permanece
en el estado Started. Una vez finalizada esta devolución de llamada, la actividad entra en el estado Resumed, y
el sistema invoca el método onResume().

onResume()

Cuando la actividad entra en el estado Resumed, pasa al primer plano y, a continuación, el sistema invoca la
devolución de llamada onResume(). Este es el estado en el que la app interactúa con el usuario. La app
permanece en este estado hasta que ocurre algún evento que la quita de foco. Tal evento podría ser, por
ejemplo, recibir una llamada telefónica, que el usuario navegue a otra actividad o que se apague la pantalla
del dispositivo.

Cuando se reanude la actividad, cualquier componente que priorice el ciclo de vida vinculado al de la actividad
recibirá el evento ON_RESUME. Aquí es donde los componentes del ciclo de vida pueden habilitar cualquier
funcionalidad que necesite ejecutarse mientras el componente está visible y en primer plano, como, por
ejemplo, iniciar una vista previa de la cámara.

Cuando se produce un evento interrumpido, la actividad entra en el estado Paused y el sistema invoca la
devolución de llamada onPause().

Si la actividad regresa al estado Resumed desde Paused, el sistema volverá a llamar al método onResume().
Por esta razón, debes implementar onResume() para inicializar los componentes que lances en onPause() y
realizar otras inicializaciones que deban ejecutarse cada vez que la actividad entre en el estado Resumed.

A continuación, se incluye un ejemplo de un componente que prioriza el ciclo de vida que accede a la cámara
cuando el componente recibe el evento ON_RESUME:

Java
public class CameraComponent implements LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void initializeCamera() {
        if (camera == null) {
            getCamera();
    }
  }

    ...
}
El código anterior inicializa la cámara una vez que LifecycleObserver recibe el evento ON_RESUME. Sin embargo,
en el modo multiventana, tu actividad puede ser totalmente visible incluso cuando se encuentra en el estado
Paused. Por ejemplo, si el usuario está en el modo multiventana y presiona la otra ventana que no contiene tu
actividad, esta se moverá al estado Paused. Si deseas que la cámara esté activa solo cuando se reanuda la app
(visible y activa en primer plano), inicializa la cámara después del evento ON_RESUME que se mostró
anteriormente. Si deseas mantener la cámara activa mientras la actividad está en el estado Paused, pero
visible (por ejemplo, en el modo multiventana), debes inicializar la cámara después del evento ON_START. No
obstante, ten en cuenta que tener la cámara activa mientras la actividad se encuentra en el estado Paused
puede impedir que otra app que se encuentre en el estado Resumed pueda acceder a la cámara en el modo
multiventana. En ocasiones, puede ser necesario mantener la cámara activa mientras la actividad está Paused,
pero, en realidad, esto podría degradar la experiencia general del usuario Piensa cuidadosamente en qué
parte del ciclo de vida es más apropiado tomar el control de los recursos compartidos del sistema en el
contexto del modo multiventana. Para obtener más información sobre la compatibilidad con ese modo,
consulta Compatibilidad con el modo multiventana.

Independientemente del evento en el que decidas realizar una operación de inicialización, asegúrate de
utilizar el evento de ciclo de vida correspondiente para liberar el recurso. Si inicializas algún evento después de
ON_START, libéralo o finalízalo después del evento ON_STOP. Si inicializas un evento después de ON_RESUME,
libéralo después de ON_PAUSE.

Ten en cuenta que el fragmento de código anterior coloca el código de inicialización de la cámara en un
componente que prioriza el ciclo de vida. En su lugar, puedes poner este código directamente en las
devoluciones de llamada del ciclo de vida de la actividad, como onStart() y onStop(), aunque esto no es
recomendable. Agregar esta lógica a un componente independiente que prioriza el ciclo de vida te permite
reutilizar el componente en varias actividades sin tener que duplicar el código. Visita Cómo administrar ciclos
de vida con componentes que los priorizan para aprender a crear un componente que priorice el ciclo de vida.

onPause()

El sistema llama a este método a modo de primera indicación de que el usuario está abandonando tu actividad
(aunque no siempre significa que está finalizando la actividad); indica que la actividad ya no está en primer
plano (aunque puede seguir siendo visible si el usuario está en el modo multiventana). Utiliza el método
onPause() para pausar o ajustar las operaciones que no deben continuar (o que deben continuar con
moderación) mientras Activity se encuentra en estado Paused, y que esperas reanudar en breve. Hay varias
razones por las que una actividad puede entrar en este estado. Por ejemplo:

 Algunos eventos interrumpen la ejecución de la app, como se describe en la sección onResume(). Este es el caso
más común.
 En Android 7.0 (API nivel 24) o versiones posteriores, varias apps se ejecutan en el modo multiventana. Debido a
que solo una de las apps (ventanas) tiene foco en cualquier momento, el sistema pausa todas las demás.
 Se abre una nueva actividad semitransparente (como un diálogo). Mientras la actividad siga siendo parcialmente
visible, pero no esté en foco, se mantendrá pausada.

Cuando la actividad pase al estado de pausa, cualquier componente que priorice el ciclo de vida vinculado al
ciclo de vida de la actividad recibirá el evento ON_PAUSE. Aquí es donde los componentes del ciclo de vida
pueden detener cualquier funcionalidad que no necesite ejecutarse mientras el componente no esté en
primer plano, como detener una vista previa de la cámara.
También puedes utilizar el método onPause() para liberar recursos del sistema, controladores de sensores
(como el GPS) o cualquier otro recurso que pueda afectar la duración de la batería mientras tu actividad esté
en pausa y el usuario no los necesite. Sin embargo, como se mencionó anteriormente en la sección
onResume(), una actividad con el estado Paused puede ser completamente visible si está en el modo
multiventana. Por eso, deberías considerar usar onStop() en lugar de onPause() para liberar o ajustar
completamente los recursos y operaciones relacionados con la IU a fin de admitir mejor el modo
multiventana.

El siguiente ejemplo de un LifecycleObserver que reacciona ante el evento ON_PAUSE es la contrapartida del
ejemplo de evento ON_RESUME anterior, que libera la cámara que se inicializó después de recibir el evento
ON_RESUME:

Java
public class JavaCameraComponent implements LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void releaseCamera() {
        if (camera != null) {
            camera.release();
            camera = null;
        }
    }

    ...
}

Ten en cuenta que el fragmento de código anterior coloca el código de liberación de la cámara después de que
LifecycleObserver recibe el evento ON_PAUSE. Como se mencionó anteriormente, consulta Cómo administrar
ciclos de vida con componentes que los priorizan para aprender a crear un componente que priorice el ciclo
de vida.

La ejecución de onPause() es muy breve y no necesariamente permite disponer de tiempo suficiente para
realizar operaciones seguras. Por esta razón, no debes utilizar onPause() para guardar los datos de la
aplicación o del usuario, realizar llamadas de red o ejecutar transacciones de la base de datos, ya que es
posible que no se complete dicho trabajo antes de que finalice el método. En su lugar, debes realizar
operaciones de finalización de cargas pesadas durante onStop(). Para obtener más información acerca de las
operaciones adecuadas para realizar durante onStop(), consulta onStop(). Para obtener más información sobre
cómo guardar datos, consulta Cómo guardar y restablecer el estado de una actividad.

La finalización del método onPause() no significa que la actividad abandone el estado Paused. Más bien, la
actividad permanecerá en ese estado hasta que se reanude o se vuelva completamente invisible para el
usuario. Si se reanuda la actividad, el sistema volverá a invocar la devolución de llamada onResume(). Si la
actividad regresa del estado Paused a Resumed, el sistema mantendrá la instancia Activity en la memoria y la
volverá a llamar cuando invoque onResume(). En esta situación, no es necesario que reinicialices los
componentes que se crearon durante los métodos de devolución de llamada que llevan al estado Resumed. Si
la actividad se vuelve completamente invisible, el sistema llamará a onStop(). En la siguiente sección, se
aborda la devolución de llamada onStop().

onStop()
Cuando el usuario ya no puede ver tu actividad, significa que ha entrado en el estado Stopped, y el sistema
invoca la devolución de llamada onStop(). Esto puede ocurrir, por ejemplo, cuando una actividad recién
lanzada cubre toda la pantalla. El sistema también puede llamar a onStop() cuando haya terminado la
actividad y esté a punto de finalizar.

Cuando la actividad pase al estado Stopped, cualquier componente que priorice el ciclo de vida vinculado al de
la actividad recibirá el evento ON_STOP. Aquí es donde los componentes del ciclo de vida pueden detener
cualquier funcionalidad que no necesite ejecutarse mientras el componente no sea visible en la pantalla.

En el método onStop(), la app debe liberar o ajustar los recursos que no son necesarios mientras no sea visible
para el usuario. Por ejemplo, tu app podría pausar animaciones o cambiar de actualizaciones de ubicación
detalladas a más generales. Usar onStop() en lugar de onPause() garantiza que continúe el trabajo relacionado
con la IU, incluso cuando el usuario esté viendo tu actividad en el modo multiventana.

También debes utilizar onStop() para realizar operaciones de finalización con un uso relativamente intensivo
de la CPU. Por ejemplo, si no encuentras un momento más oportuno para guardar información en una base de
datos, puedes hacerlo en onStop(). Por ejemplo, a continuación, se muestra una implementación de onStop()
que guarda los contenidos del borrador de una nota en el almacenamiento persistente:

Java
@Override
protected void onStop() {
    // call the superclass method first
    super.onStop();

    // save the note's current draft, because the activity is stopping


    // and we want to be sure the current note progress isn't lost.
    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

    // do this update in background on an AsyncQueryHandler or equivalent


    asyncQueryHandler.startUpdate (
            mToken,  // int token to correlate calls
            null,    // cookie, not used here
            uri,    // The URI for the note to update.
            values,  // The map of column names and new values to apply to them.
            null,    // No SELECT criteria are used.
            null     // No WHERE columns are used.
    );
}

Ten en cuenta que el código de ejemplo anterior utiliza directamente SQLite. En su lugar, deberías utilizar
Room, una biblioteca de persistencia que proporciona una capa de abstracción sobre SQLite. Para obtener
más información sobre los beneficios de usar Room y cómo implementarla en tu app, consulta la guía
Biblioteca de persistencia Room.

Cuando tu actividad entra en el estado Stopped, se mantiene el objeto Activity en la memoria: Mantiene toda
la información de estado y de miembros, pero no está vinculada al administrador de ventanas. Cuando se
reanuda la actividad, esta recuerda la información. No necesitas reinicializar los componentes que se crearon
durante los métodos de devolución de llamada que llevan al estado Resumed. El sistema también lleva un
registro del estado actual de cada objeto View en el diseño; por lo tanto, si el usuario ingresó texto en un
widget EditText, se conserva ese contenido para que no necesites guardarlo y restablecerlo.
Nota: Una vez que se detiene la actividad, el sistema puede finalizar el proceso que la contiene si necesita
recuperar memoria. Incluso si el sistema finaliza el proceso mientras la actividad está detenida, el sistema
conservará el estado de los objetos View (como el texto de un widget EditText) en un Bundle (un BLOB de
pares clave-valor) y los restablecerá si el usuario regresa a la actividad. Para obtener más información sobre
cómo restablecer una actividad a la que regresa un usuario, consulta Cómo guardar y restablecer el estado de
una actividad.

Desde el estado Stopped, la actividad regresa a interactuar con el usuario o se termina de ejecutar y
desaparece. Si regresa la actividad, el sistema llamará a onRestart(). Si se terminó de ejecutar Activity, el
sistema llamará a onDestroy(). En la siguiente sección, se explica la devolución de llamada onDestroy().

onDestroy()

Se llama a onDestroy() antes de que finalice la actividad. El sistema invoca esta devolución de llamada por los
siguientes motivos:

1. La actividad está terminando (debido a que el usuario la descarta por completo o a que se llama a finish()).
2. El sistema está finalizando temporalmente la actividad debido a un cambio de configuración (como la rotación
de la pantalla o el modo multiventana).

Cuando la actividad pase al estado Destroyed, cualquier componente que priorice el ciclo de vida vinculado al
de la actividad recibirá el evento ON_DESTROY. Aquí es donde los componentes del ciclo de vida pueden
recuperar cualquier elemento que se necesite antes de que finalice el objeto Activity.

En lugar de poner lógica en ese objeto para determinar por qué está finalizando la actividad, deberías utilizar
un objeto ViewModel a fin de contener los datos de vista relevantes para Activity. Si se va a recrear el objeto
Activity debido a un cambio de configuración, no es necesario que ViewModel realice ninguna acción, ya que
se conservará y se entregará a la siguiente instancia del objeto Activity. Si no se va a recrear el objeto Activity,
entonces ViewModel tendrá el método onCleared(), en el que podrá recuperar cualquier dato que necesite
antes de que finalice la actividad.

Puedes diferenciar estos dos casos con el método isFinishing().

Si la actividad está terminando, onDestroy() es la devolución de llamada del ciclo de vida final que recibe la
actividad. Si se llama a onDestroy() como resultado de un cambio de configuración, el sistema crea
inmediatamente una nueva instancia de actividad y luego llama a onCreate() en esa nueva instancia en la nueva
configuración.

La devolución de llamada onDestroy() debe liberar todos los recursos que aún no han sido liberados por
devoluciones de llamada anteriores, como onStop().

Estado de actividad y expulsión de memoria


El sistema finaliza los procesos cuando necesita liberar RAM; la probabilidad de que el sistema finalice un
proceso determinado dependerá del estado del proceso en ese momento. El estado del proceso, a su vez,
depende del estado de la actividad que se ejecuta en el proceso. La tabla 1 muestra la correlación entre el
estado del proceso, el estado de la actividad y la probabilidad de que el sistema finalice el proceso.
Probabilidad de que finalice Estado del proceso Estado de la actividad

Created
Menor Primer plano (en foco o por estar en él) Started
Resumed

Más Segundo plano (foco perdido) Paused

Segundo plano (no visible) Stopped


Mayor
Vacío Destroyed

Tabla 1: Relación entre el ciclo de vida del proceso y el estado de la actividad

El sistema nunca finaliza una actividad de forma directa para liberar memoria. En su lugar, finaliza el proceso
en el que se ejecuta la actividad para eliminar no solo la actividad, sino también todo lo que se ejecuta en el
proceso. Para aprender a preservar y restaurar el estado de la IU de tu actividad cuando finaliza el proceso
iniciado por el sistema, consulta Cómo guardar y restablecer el estado de una actividad.

Un usuario también puede finalizar un proceso utilizando el Administrador de aplicaciones de Configuración


para finalizar la app correspondiente.

Para obtener más información sobre los procesos en general, consulta Procesos y subprocesos. Para obtener
más información sobre cómo está ligado el ciclo de vida de un proceso a los estados de las actividades que lo
componen, consulta la sección Ciclo de vida de los procesos de esa página.

Cómo guardar y restablecer el estado transitorio de la IU


Un usuario espera que el estado de la IU de una actividad permanezca igual durante un cambio de
configuración, como la rotación de la pantalla o el cambio al modo multiventana. Sin embargo, el sistema
finaliza la actividad de forma predeterminada cuando se produce un cambio de configuración de este tipo, lo
que elimina cualquier estado de la IU almacenado en la instancia de actividad. Del mismo modo, un usuario
espera que la IU siga siendo la misma si cambia temporalmente de tu app a una diferente y luego regresa a tu
app. Sin embargo, el sistema puede finalizar el proceso de tu aplicación mientras el usuario no la esté
utilizando y tu actividad esté detenida.

Cuando finaliza la actividad debido a restricciones del sistema, debes conservar el estado transitorio de la IU
utilizando una combinación de ViewModel, onSaveInstanceState() o almacenamiento local. Para obtener más
información sobre las expectativas de los usuarios en comparación con el comportamiento del sistema y sobre
la mejor manera de preservar los datos complejos del estado de la IU en toda la actividad iniciada por el
sistema y la finalización del proceso, consulta Cómo guardar estados de IU.

En esta sección, se describe el estado de la instancia y cómo implementar el método onSaveInstance(), que es
una devolución de llamada a la actividad misma. Si los datos de tu IU son simples y ligeros, como un tipo de
datos primitivos o un objeto simple (como String), puedes utilizar onSaveInstanceState() solamente para
mantener el estado de la IU tanto en los cambios de configuración como en la finalización del proceso iniciado
por el sistema. En la mayoría de los casos, sin embargo, debes utilizar tanto ViewModel como
onSaveInstanceState() (como se describe en Cómo guardar estados de IU), ya que onSaveInstanceState() tiene
costos de serialización y deserialización.

Estado de la instancia

Existen algunas situaciones en las que finaliza tu actividad debido al comportamiento normal de la app; por
ejemplo, cuando el usuario presiona el botón Atrás o tu actividad señala su propia finalización llamando a
finish(). Cuando finaliza tu actividad porque el usuario presiona Atrás o la actividad se finaliza a sí misma, se
pierde para siempre el concepto del sistema de esa instancia Activity. En esos casos, las expectativas del usuario
coinciden con el comportamiento del sistema y no tienes trabajo adicional que hacer.

Sin embargo, si el sistema finaliza la actividad debido a restricciones (como un cambio de configuración o
presión de memoria), entonces, aunque haya desaparecido la instancia real Activity, el sistema recuerda que
existía. Si el usuario intenta volver a la actividad, el sistema crea una nueva instancia de esa actividad
utilizando un conjunto de datos guardados que describen el estado de la actividad cuando finalizó.

Los datos guardados que el sistema utiliza para restaurar el estado previo se denominan estado de instancia y
son un conjunto de pares clave-valor almacenados en un objeto Bundle. De forma predeterminada, el sistema
utiliza el Bundle de estado de instancia para guardar información de cada objeto View del diseño de tu actividad
(por ejemplo, el valor de texto ingresado en un objeto EditText). De este modo, si finaliza y se vuelve a crear la
instancia de tu actividad, se restablece el estado del diseño a su estado previo sin necesidad de que escribas el
código. Sin embargo, es posible que tu actividad tenga más información de estado que desees restablecer,
como variables de miembro que siguen el progreso del usuario en la actividad.

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

Un objeto Bundle no es apropiado para preservar más que una cantidad trivial de datos, debido a que requiere
serialización en el subproceso principal y consume memoria del proceso del sistema. Para preservar más que
una cantidad muy pequeña de datos, debes adoptar un enfoque combinado, utilizando el almacenamiento
local persistente, el método onSaveInstanceState() y la clase ViewModel, como se describe en Cómo guardar
estados de IU.

Cómo guardar un estado de IU simple y ligero usando onSaveInstanceState()

A medida que comienza a detenerse tu actividad, el sistema llama al método onSaveInstanceState() para que tu
actividad pueda guardar la información del estado en un paquete de estado de instancia. La implementación
predeterminada de ese método guarda información transitoria acerca del estado de la jerarquía de vistas de la
actividad, como el texto de un widget EditText o la posición de desplazamiento de un widget ListView.

Para guardar información adicional sobre el estado de la instancia de tu actividad, debes anular
onSaveInstanceState() y agregar pares clave-valor al objeto Bundle que se guarda en caso de que tu actividad
finalice de forma inesperada. Si sustituyes enSaveInstanceState(), debes llamar a la implementación de
superclase si deseas que la implementación predeterminada guarde el estado de la jerarquía de vistas. Por
ejemplo:
Java
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, currentScore);
    savedInstanceState.putInt(STATE_LEVEL, currentLevel);

    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

Nota: No se llama a onSaveInstanceState() cuando el usuario cierra explícitamente la actividad o en otros casos
cuando llamas a finish().

Para guardar datos persistentes, como las preferencias del usuario o información de una base de datos, debes
aprovechar las oportunidades apropiadas cuando tu actividad esté en primer plano. Si no se presenta tal
oportunidad, debes guardar esos datos durante el método onStop().

Cómo restablecer el estado de la IU de la actividad utilizando el estado de la instancia guardada

Cuando se vuelve a crear tu actividad tras haber finalizado, puedes recuperar la instancia del estado guardado
desde el Bundle que el sistema pasa a tu actividad. Los métodos de devolución de llamada onCreate() y
onRestoreInstanceState() reciben el mismo Bundle que contiene la información del estado de la instancia.

Dado que se llama al método onCreate() tanto si el sistema crea una nueva instancia de tu actividad como si
vuelve a crear una instancia previa, debes comprobar si el Bundle de estado es nulo antes de intentar leerlo. Si
es nulo, el sistema creará una instancia nueva de la actividad, en lugar de restablecer una previa que ya
finalizó.

Por ejemplo, el siguiente fragmento de código muestra cómo puedes restablecer algunos datos del estado en
onCreate():

Java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance


    if (savedInstanceState != null) {
        // Restore value of members from saved state
        currentScore = savedInstanceState.getInt(STATE_SCORE);
        currentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    // ...
}

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

Java
public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance


    currentScore = savedInstanceState.getInt(STATE_SCORE);
    currentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

Advertencia: Siempre llama a la implementación de superclase onRestoreInstanceState() para que la


implementación predeterminada pueda restablecer el estado de la jerarquía de vistas.

Navegación entre actividades


Es probable que una app entre y salga de una actividad, quizás muchas veces, durante su ciclo de vida. Por
ejemplo, el usuario puede presionar el botón Atrás del dispositivo, o la actividad puede necesitar lanzar una
actividad diferente. En esta sección, se abordan temas que necesitas saber para implementar transiciones de
actividad exitosas. Estos temas incluyen iniciar una actividad desde otra, guardar el estado de la actividad y
restablecer su estado.

Cómo iniciar una actividad desde otra

Es posible que una actividad necesite iniciar otra actividad en algún momento. Esta necesidad surge, por
ejemplo, cuando una app necesita pasar de la pantalla actual a una nueva.

En función de si la actividad desea recuperar el resultado de la nueva actividad que está a punto de comenzar,
se puede iniciar la nueva actividad utilizando los métodos startActivity() o startActivityForResult(). En cualquier
caso, debes pasar un objeto Intent.

El objeto Intent especifica la actividad exacta que quieres iniciar o describe el tipo de acción que quieres
realizar (y el sistema selecciona la actividad adecuada para ti, que incluso puede ser de otra aplicación). Un
objeto Intent también puede contener pequeñas cantidades de datos que utilizará la actividad que se inicie.
Para obtener más información sobre la clase Intent, consulta Intents y filtros de intents.

startActivity()

Si la actividad recién iniciada no necesita mostrar un resultado, la actividad actual puede iniciarla llamando al
método startActivity().
Cuando trabajes en tu propia aplicación, con frecuencia necesitarás iniciar una actividad conocida. Por
ejemplo, el siguiente fragmento de código muestra cómo lanzar una actividad llamada SignInActivity.

Java
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

Tu aplicación también podría querer realizar alguna acción, como enviar un correo electrónico, mandar un
mensaje de texto o actualizar su estado con datos de tu actividad. En ese caso, es posible que tu aplicación no
tenga actividades propias para realizar esas acciones, por lo que, en su lugar, puedes aprovechar las
actividades que proporcionan otras aplicaciones del dispositivo y que pueden realizar las acciones por ti. Aquí
es donde los intents son realmente valiosos: Puedes crear un intent que describa una acción que quieras
realizar y el sistema iniciará la actividad adecuada desde otra aplicación. Si hay varias actividades que pueden
ejecutar el intent, el usuario podrá seleccionar la que quiera usar. Por ejemplo, si quieres permitir que el
usuario envíe un mensaje de correo electrónico, puedes crear el siguiente intent:

KotlinJava
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

El EXTRA_EMAIL adicional agregado al intent es una matriz de strings de direcciones de correo electrónico a las
que se debe enviar el mensaje. Cuando una app de correo electrónico responde a este intent, lee la matriz de
strings proporcionada en el objeto adicional y las coloca en el campo "Para" del formulario de composición de
correo electrónico. En esta situación, se inicia la actividad de la app de correo electrónico y, cuando el usuario
termina, se reanuda tu actividad.

startActivityForResult()

En ocasiones, se desea obtener el resultado de una actividad cuando esta termina. Por ejemplo, puedes iniciar
una actividad que permita al usuario elegir a una persona de una lista de contactos; cuando termina, muestra
a la persona seleccionada. Para ello, llama al método startActivityForResult(Intent, int), donde el parámetro
entero identifica la llamada. Este identificador sirve para desambiguar entre varias llamadas a
startActivityForResult(Intent, int) de la misma actividad. No es un identificador global y no corre el riesgo de
entrar en conflicto con otras apps o actividades. El resultado se obtiene a través de tu método
onActivityResult(int, int, Intent).

Cuando se lleva a cabo una actividad secundaria, puedes llamar a setResult(int) para mostrarle los datos a la
actividad superior. La actividad secundaria siempre debe proporcionar un código de resultado, que pueden ser
los resultados estándar RESULT_CANCELED, RESULT_OK o cualquier valor personalizado que comience con
RESULT_FIRST_USER. Además, la actividad secundaria puede mostrar opcionalmente un objeto Intent que
contenga cualquier dato adicional que desee. La actividad superior utiliza el método onActivityResult(int, int,
Intent), junto con el identificador entero que la actividad superior brindó originalmente, para recibir la
información.
Si una actividad secundaria falla por cualquier razón, por ejemplo, debido a un bloqueo, la actividad superior
recibirá un resultado con el código RESULT_CANCELED.

Java
public class MyActivity extends Activity {
     // ...

     static final int PICK_CONTACT_REQUEST = 0;

     public boolean onKeyDown(int keyCode, KeyEvent event) {


         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             // When the user center presses, let them pick a contact.
             startActivityForResult(
                 new Intent(Intent.ACTION_PICK,
                 new Uri("content://contacts")),
                 PICK_CONTACT_REQUEST);
            return true;
         }
         return false;
     }

     protected void onActivityResult(int requestCode, int resultCode,


             Intent data) {
         if (requestCode == PICK_CONTACT_REQUEST) {
             if (resultCode == RESULT_OK) {
                 // A contact was picked.  Here we will just display it
                 // to the user.
                 startActivity(new Intent(Intent.ACTION_VIEW, data));
             }
         }
     }
 }

Cómo coordinar actividades

Cuando una actividad inicia otra, ambas experimentan transiciones en su ciclo de vida. La primera actividad
deja de funcionar y entra en el estado Paused o Stopped, mientras que la otra actividad se crea. Si esas
actividades comparten datos guardados en el disco o en alguna otra parte, es importante que entiendas que la
primera actividad no se detiene completamente antes de que se cree la segunda. Más bien, el proceso de
iniciar la segunda se superpone con el proceso de detener la primera.

El orden de las devoluciones de llamada del ciclo de vida está bien definido, especialmente cuando las dos
actividades están en el mismo proceso (app) y una inicia la otra. Aquí te mostramos el orden de las
operaciones que ocurren cuando la actividad A inicia la actividad B:

1. Se ejecuta el método onPause() de la actividad A.


2. Los métodos onCreate(), onStart() y onResume() de la actividad B se ejecutan en secuencia. (Ahora la actividad B
tiene la atención del usuario).
3. Por lo tanto, si la actividad A deja de verse en pantalla, se ejecuta su método onStop().
Esta secuencia predecible de devoluciones de llamada del ciclo de vida te permite administrar la transición de
información de una actividad a otra.

También podría gustarte