Tareas y la pila de actividades

Una tarea es un conjunto de actividades con las que los usuarios interactúan cuando intentan hacer algo en tu aplicación. Estas actividades se organizan en una pila llamada pila de actividades en el orden en que se abre cada actividad.

Por ejemplo, una app de correo electrónico podría tener una actividad para mostrar una lista de mensajes nuevos. Cuando el usuario selecciona un , se abrirá una nueva actividad para ver ese mensaje. Se agrega esta nueva actividad a la pila de actividades. Luego, cuando el usuario presiona o hace un gesto hacia atrás, esa nueva actividad finaliza y se quita de la pila.

Ciclo de vida de una tarea y su pila de actividades

La pantalla principal del dispositivo es el punto de partida de la mayoría de las tareas. Cuando un usuario toca el ícono de una app o un acceso directo en el selector de aplicaciones o en la pantalla principal la tarea de esa app pasa a primer plano. Si no existe una tarea para la app, se mostrará se crea una tarea nueva y se crea la principal actividad de esa app cuando se abre como actividad raíz en la pila.

Cuando la actividad actual inicia otra actividad, la actividad nueva pasa a la parte superior. de la pila y se enfoca. La actividad anterior permanece en la pila, pero se detuvo. Cuando se detiene una actividad, el sistema conserva el estado actual de su interfaz de usuario. Cuando el usuario realiza la acción de volver, la actividad actual se que salieron de la parte superior de la pila y se destruyeron. El se reanuda la actividad anterior y se restablece el estado previo de su IU.

Actividades en la de la pila nunca se reordenan, solo se insertan y se quitan de la pila a medida que se iniciada por la actividad actual y descartada por el usuario a través del botón o gesto Atrás. Por lo tanto, la pila de actividades funciona como una estructura de objetos último en entrar, primero en salir. En la figura 1, se muestra un cronograma con que se insertan y se salen de una pila de actividades.

Figura 1: Una representación de cómo cada nueva actividad en una tarea agrega un elemento a la pila de actividades Cuando el usuario presiona o hace un gesto Atrás, se destruye la actividad actual y la actividad anterior currículums.

A medida que el usuario presiona o hace un gesto hacia atrás, cada actividad de la pila se quita para revelar el anterior, hasta que el usuario vuelve a la página principal o a la actividad que se estaba ejecutando cuando comenzó la tarea. Cuando todas las actividades se quitan de la pila, la tarea ya no existe.

Comportamiento de retroceso para actividades de selector raíz

Las actividades del selector raíz son actividades que declaran un intent filtrar con ambos ACTION_MAIN y CATEGORY_LAUNCHER. Estas actividades son únicas porque actúan como puntos de entrada a tu aplicación desde el selector de aplicaciones y se usan para iniciar una tarea.

Cuando un usuario presiona o hace un gesto hacia atrás desde una actividad de selector raíz, el sistema maneja el evento de manera diferente según la versión de Android a la que se esté ejecutando el dispositivo.

Comportamiento del sistema en Android 11 y versiones anteriores
El sistema finaliza la actividad.
Comportamiento del sistema en Android 12 y versiones posteriores

El sistema mueve la actividad y su tarea a segundo plano en lugar de finalizando la actividad. Este comportamiento coincide con el comportamiento predeterminado del sistema cuando navegar fuera de una app con el botón de inicio o el gesto

En la mayoría de los casos, este comportamiento significa que los usuarios pueden reanudar tu app más rápido. de un estado semicaliente, en lugar de tener que reiniciar completamente la app desde una red estado.

Si necesitas proporcionar una navegación hacia atrás personalizada, recomendamos usar las APIs de actividad de AndroidX en lugar de anular onBackPressed() Las APIs de actividad de AndroidX difieren automáticamente al un comportamiento adecuado del sistema si no hay componentes que lo intercepten Presiona Atrás.

Sin embargo, si tu app anula onBackPressed() para procesar. Navegación hacia atrás y finaliza la actividad, actualiza tu implementación para llamar a super.onBackPressed() en lugar de finalizar. Llamando super.onBackPressed() mueve la actividad y su tarea a segundo plano cuando apropiado y proporciona una experiencia de navegación más coherente para los usuarios en las apps.

Tareas en primer y segundo plano

Figura 2: Dos tareas: la tarea B recibe la interacción del usuario en en primer plano, mientras que la Tarea A está en segundo plano, a la espera de a tu currículum.

Una tarea es una unidad cohesiva que puede pasar a segundo plano cuando un usuario inicia una nueva tarea o te dirige a la pantalla principal. En segundo plano, todas las actividades de la tarea se detienen, pero la pila de actividades de la tarea permanece intacta (es decir, pierde el foco mientras se lleva a cabo otra tarea, como se muestra en la figura 2. R la tarea puede volver a primer plano para que los usuarios puedan continuar desde donde la dejaron desactivado.

Considera el siguiente flujo de tareas para la Tarea A actual que tiene tres actividades en su pila, incluidas dos en la actividad actual:

  1. El usuario utiliza el botón de inicio o el gesto y, luego, inicia una nueva app desde el selector de aplicaciones.

    Cuando aparece la pantalla principal, la tarea A pasa a segundo plano. Cuando la nueva se inicia la app, el sistema inicia una tarea para esa app (tarea B) con su propia pila de actividades.

  2. Luego de interactuar con esa app, el usuario vuelve a la pantalla principal y selecciona que originalmente inició la Tarea A.

    Ahora, la Tarea A pasa al primer plano; las tres actividades de la pila se intacto, y se reanuda la actividad de la parte superior de la pila. En este punto, el el usuario también puede volver a la Tarea B si se dirige a la pantalla principal y selecciona el ícono de la app que inició esa tarea o seleccionando la tarea de la aplicación desde la pestaña Recientes pantalla.

Varias instancias de actividad

Figura 3: Se pueden crear varias instancias de una sola actividad veces.

Como las actividades de la pila de actividades nunca se reordenan, si tu app permite a los usuarios iniciar una actividad específica desde más de una actividad, una nueva de esa actividad se crea y se envía a la pila, en lugar de llevar cualquier instancia anterior de la actividad a la parte superior. Por lo tanto, uno de actividad de tu app podrían crearse varias veces, incluso desde diferentes tareas, como se muestra en la figura 3.

Si el usuario navega hacia atrás con el botón Atrás botón o gesto, las instancias de la actividad se revelan en el orden en que abierto, cada uno con su propio estado de IU. Sin embargo, puedes modificar este si no quieres que se generen instancias de una actividad más de una vez. Aprendizaje más información en la sección sobre administración de tareas.

Entornos multiventana

Cuando las apps se ejecutan simultáneamente en un modo multiventana entorno de desarrollo, compatible con Android 7.0 (API nivel 24) y versiones posteriores, el sistema administra tareas por separado para cada ventana. Cada la ventana puede tener varias tareas. Lo mismo sucede con las aplicaciones de Android que se ejecutan Chromebooks: El sistema administra tareas, o grupos de tareas, en una por ventana.

Resumen del ciclo de vida

A continuación, se resume el comportamiento predeterminado de las actividades y tareas:

  • Cuando la actividad A inicia la actividad B, la actividad A se detiene, pero el sistema conserva su estado, como la posición de desplazamiento y el texto ingresado en los formularios. Si el usuario presiona o usa el gesto de retroceso mientras se encuentra en la actividad B y la actividad A se reanuda con su estado restablecido.

  • Cuando el usuario abandona una tarea con el botón o el gesto de inicio, el estado la actividad se detiene y su tarea pasa a segundo plano. El sistema retiene el estado de cada actividad en la tarea. Si, más tarde, el usuario reanuda la tarea seleccionando el ícono de selector que inició la tarea, esta llega a en primer plano y reanuda la actividad en la parte superior de la pila.

  • Si el usuario presiona o hace un gesto hacia atrás, se quitará la actividad actual de la pila y destruir. Se reanudará la actividad anterior de la pila. Cuándo se destruye una actividad, el sistema no retiene el estado de la actividad.

    Este comportamiento es diferente para las actividades de selector raíz Cuando la app se ejecuta en un dispositivo con Android 12 o versiones posteriores.

  • Puedes crear instancias de las actividades varias veces, incluso desde otras tareas.

Administra tareas

Android administra las tareas y la pila de actividades colocando todas las actividades iniciadas una sucesión en la misma tarea, en una última en, primero de una pila. Esto funciona muy bien para la mayoría de las apps y, por lo general, no tienes que preocuparte por cómo se asocian tus actividades con las tareas o cómo están al fondo en una pila.

Sin embargo, puedes decidir que quieres interrumpir el comportamiento normal. Por ejemplo, es posible que desees que una actividad de tu aplicación comience una tarea nueva cuando sea comenzaste, en lugar de colocarse dentro de la tarea actual. O bien, cuando comienzas un actividad, es posible que desees presentar una instancia existente de esta, en lugar de crear una instancia nueva sobre la pila de actividades. O quizás quieres que tu pila de actividades se borre de todas las actividades, excepto la actividad raíz. cuando el usuario abandona la tarea.

Puedes hacer todo esto y más con los atributos en la Elemento del manifiesto <activity> y marcas en el intent que pasas a startActivity()

Estos son los atributos <activity> principales que puedes usar para administrar tareas:

Estas son las principales marcas de intent que puedes usar:

En las siguientes secciones, se explica cómo usar estos atributos del manifiesto y marcas de intent para definir cómo se asocian las actividades con las tareas y cómo se comportan en la pila de actividades.

También se analizan las consideraciones sobre cómo las tareas y actividades se representan y administran en la pantalla Recientes. Por lo general, se deja que el define cómo se representan tu tarea y tus actividades en el Recientes. No necesitas modificar este comportamiento. Para ver más consulta la pantalla Recientes.

Cómo definir modos de inicio

Los modos de lanzamiento te permiten definir cómo se asocia una nueva instancia de una actividad con la tarea actual. Puedes definir los modos de lanzamiento de dos maneras, tal como se describe en las siguientes secciones:

Entonces, si la actividad A inicia la actividad B, la actividad B puede definirla en su manifiesto. cómo se asocia con la tarea actual, y la actividad A puede usar una marca de intent para solicitar cómo la actividad B puede asociarse con la tarea actual.

Si ambos las actividades definen cómo la actividad B se asocia con una tarea; entonces, la actividad de la actividad B, como se define en el intent, se respeta por sobre la solicitud de la actividad B, como definido en su manifiesto.

Cómo definir modos de inicio con el archivo de manifiesto

Cuando declaras una actividad en tu archivo de manifiesto, puedes especificar la actividad se asocia con una tarea mediante la del elemento <activity> atributo launchMode.

Existen cinco modos de inicio que puedes asignar al atributo launchMode:

  1. "standard"
    Es el modo predeterminado. El sistema crea una nueva instancia de la actividad en la tarea. desde donde se inició y enruta el intent hacia él. La actividad se puede se crearon instancias múltiples veces, cada instancia puede pertenecer a diferentes tareas y una tarea puede tener varias instancias.
  2. "singleTop"
    Si ya existe una instancia de la actividad en la parte superior de la tarea actual, el sistema enruta el intent a esa instancia a través de una llamada a su onNewIntent() en lugar de crear una nueva instancia de la actividad. La actividad es se crearon instancias múltiples veces, cada una puede pertenecer a diferentes tareas, y una tarea puede tener varias instancias (pero solo si la actividad de la parte superior de la pila de actividades no es una instancia existente de la actividad).

    Por ejemplo, supongamos que la pila de actividades de una tarea consta de la actividad raíz A con las actividades B, C y D en la parte superior (de modo que la pila es A-B-C-D, con D en la parte superior). Un intent llega para una actividad de tipo D. Si D tiene el inicio predeterminado "standard" , se lanza una instancia nueva de la clase y la pila se convierte en A-B-C-D-D. Sin embargo, si el modo de lanzamiento de D es "singleTop", la instancia existente de D recibe el intent a través de onNewIntent(), porque está en la parte superior de la pila, y la pila sigue siendo A-B-C-D. Si: por otro lado, de destino llega a una actividad de tipo B, y luego se agrega una nueva instancia de B a la pila, incluso si su modo de inicio es "singleTop".

  3. "singleTask"
    El sistema crea la actividad en la raíz de una tarea nueva o localiza la actividad en una tarea existente con la misma afinidad. Si una instancia del si ya existe actividad, el sistema enruta a la instancia existente a través de una llamada a su onNewIntent() en lugar de crear una instancia nueva. Mientras tanto, las actividades que están sobre él se destruyen.
  4. "singleInstance".
    El comportamiento es el mismo que en "singleTask", con la excepción de que el sistema no inicia ningún otro en la tarea que contiene la instancia. La actividad siempre es el único miembro de su tarea. Todas las actividades que esta inicie se abrirán en en una tarea separada.
  5. "singleInstancePerTask".
    La actividad solo puede ejecutarse como la actividad raíz de la tarea; la primera la actividad que creó la tarea y, por lo tanto, solo puede haber una de esta actividad en una tarea. A diferencia del modo de lanzamiento singleTask, esta la actividad puede iniciarse en varias instancias y en distintas tareas si el FLAG_ACTIVITY_MULTIPLE_TASK o FLAG_ACTIVITY_NEW_DOCUMENT esté establecida.

A modo de ejemplo, la app de navegador de Android declara que el navegador web La actividad siempre se abre en su propia tarea especificando singleTask. modo de lanzamiento en el <activity> . Esto significa que, si tu app emite un intent para abrir la app de Android, navegador, su actividad no se coloca en la misma tarea que tu app. En cambio, se inicia una nueva tarea para el navegador o, si el navegador ya tiene una tarea, que se ejecuta en segundo plano, se presenta la tarea para que administre la nueva .

Independientemente de si una actividad se inicia en una tarea nueva o en la misma tarea que la actividad que la inició, el botón Atrás y el gesto siempre toman usuario a la actividad anterior. Sin embargo, si inicias una actividad que especifica el modo de lanzamiento singleTask, y existe una instancia de esa actividad en una tarea en segundo plano, toda esa tarea pasa al primer plano. En este punto, la pila de actividades incluye todas las actividades de la tarea que se presentó en el parte superior de la pila. En la Figura 4, se muestra este tipo de situación.

Figura 4: Una representación de cómo una actividad con lanzamiento el modo "singleTask" se agrega a la pila de actividades. Si la actividad ya es parte de una tarea en segundo plano con su propia pila de actividades, toda la pila de actividades también avanza, encima de la tarea.

Para obtener más información sobre el uso de los modos de inicio en el archivo de manifiesto, consulta la Documentación del elemento <activity>

Cómo definir modos de inicio con marcas de intents

Al iniciar una actividad, puedes modificar la asociación predeterminada de una actividad a su tarea incluyendo marcas en el intent que le entregues startActivity() Las marcas que puedes usar para modificar el comportamiento predeterminado son las siguientes:

FLAG_ACTIVITY_NEW_TASK

El sistema inicia la actividad en una tarea nueva. Si ya se está ejecutando una tarea durante el actividad de inicio, esa tarea pasa a primer plano con su último estado restablecido, y la actividad recibe el nuevo intent en onNewIntent()

Esto produce el mismo comportamiento que "singleTask". Se analizó el valor de launchMode en la sección anterior.

FLAG_ACTIVITY_SINGLE_TOP

Si la actividad que se está iniciando es la actual, en la parte superior de la parte posterior en la pila, la instancia existente recibe una llamada onNewIntent() en lugar de crear una nueva instancia de la actividad.

Esto produce el mismo comportamiento que "singleTop". launchMode analizado en la sección anterior.

FLAG_ACTIVITY_CLEAR_TOP

Si la actividad que se inicia ya se está ejecutando en la tarea actual, luego, en lugar de iniciar una instancia nueva de esa actividad, el sistema destruye todas las demás actividades que le siguen. El intent es entregados a la instancia reanudada de la actividad, ahora en la parte superior, mediante onNewIntent()

No existe un valor para el atributo launchMode que produce este comportamiento.

FLAG_ACTIVITY_CLEAR_TOP se usa con mayor frecuencia junto con FLAG_ACTIVITY_NEW_TASK Cuando se usan juntas, estas marcas ubicar una actividad existente en otra tarea y colocarla en una posición en la que puede responder al intent.

Cómo administrar afinidades

Una afinidad indica qué tarea "prefiere una actividad" a la que pertenece. De De forma predeterminada, todas las actividades de la misma aplicación tienen afinidad entre sí: que "preferen" estén en la misma tarea.

Sin embargo, puedes modificar la afinidad predeterminada de una actividad. Actividades definidas En diferentes apps pueden compartir afinidad, y las actividades definidas en la misma app se les pueden asignar diferentes afinidades de tareas.

Puedes modificar la afinidad de una actividad con taskAffinity. atributo de <activity> .

El atributo taskAffinity toma un valor de cadena que debe ser diferente de el nombre del paquete predeterminado declaradas en la <manifest> ya que el sistema usa ese nombre para identificar la tarea predeterminada afinidad para la app.

La afinidad entra en juego en dos circunstancias:

  1. Cuando el intent que inicia una actividad contiene el FLAG_ACTIVITY_NEW_TASK marca.

    De forma predeterminada, se lanza una actividad nueva en la tarea de la actividad que se llamó startActivity() Se coloca en la misma pila de actividades que el emisor.

    Sin embargo, si el intent que se pasa a startActivity() contiene el FLAG_ACTIVITY_NEW_TASK , el sistema busca una tarea diferente para alojar la nueva actividad. A menudo, esta es una tarea nueva. Sin embargo, no es necesario que lo sea. Si hay un elemento tarea existente con la misma afinidad que la actividad nueva, la actividad se lanza en esa tarea. De lo contrario, se inicia una nueva tarea.

    Si esta marca hace que una actividad comience una tarea nueva y el usuario utiliza el botón de inicio o un gesto para salir, debe haber alguna manera para que el usuario volver a la tarea. Algunas entidades, como el administrador de notificaciones, siempre inician actividades en una tarea externa, nunca como parte de ellas, por lo que siempre ponen FLAG_ACTIVITY_NEW_TASK en los intents que pasan a startActivity()

    Si una entidad externa que podría usar esta marca puede invocar tu actividad, asegúrate de que el usuario tenga independiente de volver a la tarea que se ha iniciado, por ejemplo, con un icono de selector, donde la actividad raíz de la tarea tiene un CATEGORY_LAUNCHER filtro de intents. Para obtener más información, consulta la sección sobre cómo iniciar tareas.

  2. Cuando una actividad tiene su allowTaskReparenting establecido en "true".

    En este caso, la actividad puede pasar de la tarea en la que inicia a la tarea que tiene. una afinidad cuando la tarea pasa a primer plano.

    Por ejemplo, imagina una actividad que informa las condiciones climáticas en Las ciudades seleccionadas se definen como parte de una app de viajes. Tiene la misma afinidad que otras actividades en la misma app, la afinidad de app predeterminada, y puede con este atributo.

    Cuando una de tus actividades comienza, de informes meteorológicos, inicialmente pertenece a la misma tarea que tu actividad. Sin embargo, cuando la tarea de la app de viajes pasa a primer plano, el la actividad de informes meteorológicos se reasigna a esa tarea y se muestra dentro de ella.

Borra la pila de actividades

Si el usuario abandona una tarea durante mucho tiempo, el sistema la borra de todas excepto la actividad raíz. Cuando el usuario vuelve a la tarea, solo se restablece la actividad raíz. El sistema se comporta de esta manera según suponiendo que después de un Mayor cantidad de tiempo que los usuarios abandonan lo que estaban haciendo antes y vuelven a la tarea para comenzar algo nuevo.

Existen algunos atributos de actividades que puedes utilizar para modificar este comportamiento:

alwaysRetainTaskState
Cuando este atributo se establece en "true" en la actividad raíz de una tarea, el elemento el comportamiento predeterminado que acabamos de describir no ocurre. La tarea retiene todo actividades de la pila, incluso luego de un período prolongado.
clearTaskOnLaunch

Cuando este atributo se establece en "true" en la actividad raíz de una tarea, esta se borra hasta la actividad raíz cada vez que el usuario sale de la tarea y regresa a él. En otras palabras, es lo opuesto a alwaysRetainTaskState El el usuario siempre vuelve a la tarea en su estado inicial, incluso después de dejar tarea solo por un momento.

finishOnTaskLaunch

Este atributo es como clearTaskOnLaunch, pero opera en una sola actividad, no en toda una tarea. También puede provocar que finalice cualquier actividad, excepto la actividad raíz. Cuando se establece en "true", la actividad seguirá siendo parte de la tarea solo durante la sesión actual. Si el usuario sale de la tarea y luego vuelve a ella, dejará de estar presente.

Cómo iniciar una tarea

Puedes configurar una actividad como punto de entrada para una tarea proporcionándole un intent filtra con "android.intent.action.MAIN" como la acción especificada "android.intent.category.LAUNCHER" como la categoría especificada:

<activity ... >
    <intent-filter ... >
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    ...
</activity>

Un filtro de intents de este tipo hace que un ícono y una etiqueta para la actividad mostrar en el selector de aplicaciones, lo que brinda a los usuarios una forma de iniciar la actividad y de volver a la tarea que crea en cualquier momento después del inicio.

Esta segunda capacidad es importante. Los usuarios deben poder abandonar una tarea y, luego, y regresa más tarde con este selector de actividades. Por este motivo, solo utiliza los dos modos de inicio que marcan actividades como que siempre inician una tarea, "singleTask" y "singleInstance", cuando la actividad tiene un elemento ACTION_MAIN y un CATEGORY_LAUNCHER filtro.

Imagina, por ejemplo, qué podría suceder si falta el filtro: un el intent inicia una actividad "singleTask", lo cual inicia una tarea nueva, y el usuario dedica algún tiempo a esa tarea. Luego, el usuario utiliza el botón de inicio o gesto. La tarea ahora se envía al segundo plano y deja de estar visible. Ahora, el usuario no tiene forma de volver a la tarea porque no está representada en la app de Google.

En los casos en los que no deseas que el usuario pueda regresar a una actividad, establece el <activity> finishOnTaskLaunch del elemento a "true". Para obtener más información, consulta la sección sobre cómo borrar la pila de actividades.

Más información sobre cómo se representan y administran las tareas y actividades en la pantalla Recientes está disponible en Recientes pantalla.

Más recursos