Comprender la actividad de Android launchMode: estándar, singleTop, singleTask y singleInstance

La traducción del artículo fue preparada especialmente para estudiantes avanzados en desarrollo de Android .




La actividad es uno de los conceptos más llamativos en Android (el sistema operativo móvil más popular con una arquitectura de gestión de memoria bien diseñada que implementa perfectamente la multitarea).

De una forma u otra, con el lanzamiento de Activity en la pantalla, no todo es tan simple. La forma en que se ejecutó también es importante. Hay muchos matices en este tema. Uno de los realmente importantes es launchMode , del que hablaremos en este artículo.

Cada actividad se crea para trabajar con diferentes objetivos. Algunos de ellos están diseñados para trabajar por separado con cada intento, por ejemplo, actividad enviada para redactar correos electrónicos en el cliente de correo. Mientras que otros están diseñados para funcionar como un singleton, como un buzón de actividad.

Es por eso que es importante indicar si necesita crear una nueva Actividad o usar una existente, de lo contrario, puede provocar una mala experiencia de usuario o fallas. Gracias a los desarrolladores del kernel de Android, esto es fácil de hacer con launchMode , que fue diseñado específicamente para esto.

Definición de LaunchMode


Esencialmente, podemos definir launchMode directamente como un atributo de etiqueta <activity>en AndroidManifest.xml:

<activity
    android:name=".SingleTaskActivity"
    android:label="singleTask launchMode"
    android:launchMode="singleTask">

Hay 4 tipos de launchMode disponibles. Echemos un vistazo a ellos uno a la vez.

estándar

Este es el modo predeterminado.

El comportamiento de una Actividad establecida en este modo siempre creará una nueva Actividad para trabajar por separado con cada Intento enviado. De hecho, si se enviaron 10 Intentos para redactar un correo electrónico, se deben lanzar 10 Actividades para servir cada Intento por separado. Como resultado, se puede iniciar un número ilimitado de tales Actividades en el dispositivo.

Comportamiento en Android pre-Lollipop

Este tipo de actividad se creará y se colocará en la parte superior de la pila en la misma tarea que envió la intención.



La siguiente imagen muestra lo que sucede cuando compartimos la imagen con la Actividad estándar. Se apilará en la misma tarea descrita anteriormente, aunque son de diferentes aplicaciones.



Y esto es lo que verá en el administrador de tareas. (Puede parecer un poco extraño)



Si cambiamos la aplicación a otra tarea y luego volvemos a la Galería, aún veremos que el modo de lanzamiento estándar se coloca encima de la tarea Galería. Como resultado, si necesitamos hacer algo en la Galería, primero debemos terminar nuestro trabajo en esta Actividad adicional.

Comportamiento en Android Lollipop

Si estas actividades se relacionan con la misma aplicación, el comportamiento será el mismo que en la implementación previa a Lollipop, colocando en la pila encima de la tarea.



Pero en caso de que la intención se envíe desde otra aplicación, se creará una nueva tarea y la actividad recién creada se colocará como raíz, como se muestra a continuación.



Esto es lo que verá en el administrador de tareas.



Esto se debe a que el sistema de gestión de tareas se ha modificado en Lollipop, se ha vuelto mejor y más comprensible. En Lollipop, simplemente puede volver a la Galería, ya que está en una tarea diferente. Puede enviar otra intención, se creará una nueva tarea que servirá a la intención de la misma manera que la anterior.



Un ejemplo de este tipo de actividad es Redactar actividad de correo electrónico o actividad de publicación de estado de redes sociales(actualización de estado en redes sociales). Si tiene una Actividad en mente que procesa cada Intento por separado, entonces está pensando en una Actividad estándar .

singleTop


El siguiente modo es singleTop . Se comporta de la misma manera que el estándar , lo que significa que puede crear tantas instancias de SingleTop Activity como queramos. La única diferencia es que si ya hay una instancia de Actividad con el mismo tipo en la parte superior de la pila en la tarea de llamada, no se creará ninguna Actividad nueva, en cambio, el Intento se enviará a la instancia de Actividad existente a través del método onNewIntent().



En el modo SingleTop, debe considerar manejar la intención entrante onCreate()y onNewIntent()para que funcione en todos los casos.

Un ejemplo de uso de este modo es la función de búsqueda. Pensemos en crear un cuadro de búsqueda que lo dirija a SearchActivity para ver los resultados de la búsqueda. Para una mejor experiencia de usuario, generalmente siempre ponemos el cuadro de búsqueda en la página de resultados de búsqueda para permitir al usuario realizar la siguiente búsqueda sin volver atrás.

Ahora imagine que si siempre lanzamos una nueva SearchActivity para servir un nuevo resultado de búsqueda, obtendremos 10 nuevas actividades para 10 iteraciones de la búsqueda. Sería muy extraño regresar, ya que tendría que hacer clic 10 veces para revisar todos los resultados de búsqueda y volver a la Actividad raíz.

En cambio, si SearchActivity ya está en la parte superior de la pila, es mejor enviar un Intento a una instancia de Actividad existente y dejar que actualice el resultado de la búsqueda. Ahora solo habrá una SearchActivity ubicada en la parte superior de la pila, y simplemente puede hacer clic en el botón Atrás una vez para volver a la Actividad anterior. Eso tiene más sentido.

En cualquier caso, singleTop funciona en la misma tarea que la persona que llama. Si espera que la intención se envíe a una actividad existente, colocada encima de cualquier otra tarea, debería decepcionarlo diciendo que allí ya no funciona. En caso de que la intención se envíe desde otra aplicación a singleTop Activity, la nueva actividad se lanzará en el mismo aspecto que para standart launchMode (pre-Lollipop: colocado encima de la tarea de llamada, Lollipop: se creará una nueva tarea) .

SingleTask


Este modo es muy diferente de standart y singleTop. La actividad con singleTask launchMode solo puede tener una instancia en el sistema (ala singleton) . Si ya existe una instancia de Actividad en el sistema, toda la tarea que contiene la instancia se moverá hacia arriba y la Intención se proporcionará a través del método onNewIntent(). De lo contrario, se creará una nueva Actividad y se colocará en la tarea correspondiente.

Trabajar en una aplicación

Si no hubo una sola instancia de Actividad de Tarea en el sistema, se creará una nueva y simplemente se colocará en la pila en la misma tarea.



Pero si existe, todas las Actividades ubicadas encima de esta Actividad de Tarea única se destruirán brutalmente de manera automática (el ciclo de vida se completa) para mostrar la Actividad deseada en la parte superior de la pila.Al mismo tiempo, la intención se enviará a SingleTask Activity a través de un método maravilloso onNewIntent().



No tiene sentido desde el punto de vista de la experiencia del usuario, pero está diseñado de esta manera ...

Puede notar un matiz que se menciona en la documentación :

el sistema crea una nueva tarea e instancia una instancia de actividad en la raíz de la nueva tarea.

Pero en la práctica, parece que esto no funciona como se describe . SingleTask Activity todavía se coloca en la parte superior de la pila de Actividad de la tarea, como se puede ver en el resultado del comando dumpsys activity.

Ejército de reserva

sk id #239
  TaskRecord{428efe30 #239 A=com.thecheesefactory.lab.launchmode U=0 sz=2}
  Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.thecheesefactory.lab.launchmode/.StandardActivity }
    Hist #1: ActivityRecord{429a88d0 u0 com.thecheesefactory.lab.launchmode/.SingleTaskActivity t239}
      Intent { cmp=com.thecheesefactory.lab.launchmode/.SingleTaskActivity }
      ProcessRecord{42243130 18965:com.thecheesefactory.lab.launchmode/u0a123}
    Hist #0: ActivityRecord{425fec98 u0 com.thecheesefactory.lab.launchmode/.StandardActivity t239}
      Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.thecheesefactory.lab.launchmode/.StandardActivity }
      ProcessRecord{42243130 18965:com.thecheesefactory.lab.launchmode/u0a123}

Si desea que SingleTask Activity se comporte como se describe en el documento: cree una nueva tarea y coloque Activity como la Actividad raíz. taskAffinityDebe definir un atributo para la actividad SingleTask de la siguiente manera.

<activity
    android:name=".SingleTaskActivity"
    android:label="singleTask launchMode"
    android:launchMode="singleTask"
    android:taskAffinity="">

Ese será el resultado cuando intentemos correr SingleTaskActivity.





Su tarea es decidir si usar taskAffinityo no, dependiendo del comportamiento deseado de la Actividad.

Interactuar con otra aplicación

Tan pronto como se envíe el Intento desde otra aplicación y no se haya creado ninguna instancia de la Actividad en el sistema, se creará una nueva tarea con una nueva Actividad colocada como Actividad raíz.





Si no hay ninguna tarea que sea el propietario de la actividad de la tarea única que realiza la llamada, se mostrará una nueva actividad.



Si existe una instancia de una Actividad en una tarea, toda la tarea se moverá hacia arriba, y para cada Actividad individual ubicada por encima de una Actividad de Tarea única, se completará el ciclo de vida. Si se presiona el botón Atrás, el usuario debe pasar por la Actividad en la pila antes de regresar a la tarea de llamada.



Un ejemplo de uso de este modo es cualquier Actividad de punto de entrada, por ejemplo, la página Bandeja de entrada de un cliente de correo electrónico o una línea de tiempo de una red social. Estas actividades no suponen más de una instancia, por lo que singleTask hará su trabajo perfectamente. En cualquier caso, debe usar este modo sabiamente, ya que en este modo las Actividades pueden destruirse sin la confirmación del usuario, como se describió anteriormente.

única instancia


Este modo es muy similar a singleTask, donde solo podría existir una instancia de una Actividad en un sistema. La diferencia es que una tarea que tiene esta Actividad solo puede tener una Actividad, una que tenga un atributo SingleInstance . Si se llama a otra Actividad desde este tipo de Actividad, se crea automáticamente una nueva tarea para acomodar esta nueva Actividad. Del mismo modo, si se llama a la actividad singleInstance, se creará una nueva tarea para alojar esta actividad.

En cualquier caso, el resultado es bastante extraño. De la información proporcionadadumpsys, está claro que hay dos tareas en el sistema, pero solo una aparece en el administrador de tareas, dependiendo de cuál esté en la parte superior. Como resultado, aunque hay una tarea que todavía se está ejecutando en segundo plano, no podemos volver a ponerla en primer plano. No tiene ningún sentido.

Esto es lo que sucede cuando se llama a una sola actividad de entrada mientras ya existe una actividad en la pila.



Y aquí está lo que vemos en el administrador de tareas.



Dado que esta tarea solo puede tener una Actividad, ya no podemos volver a la tarea No. 1. La única forma de hacerlo es reiniciar la aplicación desde el iniciador, pero, como resultado, la tarea singleInstance se ocultará en segundo plano.

De todos modos, hay algunas soluciones para este problema. Al igual que con SingleTask Activity, simplemente asigne un atributo taskAffinitya singleInstance Activity, permitiendo que existan múltiples tareas en el administrador de tareas.

<activity
    android:name=".SingleInstanceActivity"
    android:label="singleInstance launchMode"
    android:launchMode="singleInstance"
    android:taskAffinity="">

Ahora la imagen tiene más sentido.



Este modo rara vez se usa. Algunos de los casos de uso prácticos son un iniciador de actividad o una aplicación para la cual está 100% seguro de que solo debe haber una actividad. En cualquier caso, le sugiero que no use este modo, a menos que haya una emergencia.

Banderas de intenciones


Además AndroidManifest.xmlde establecer el modo de inicio directamente en , también podemos ajustar el comportamiento utilizando una herramienta llamada Indicadores de intención , por ejemplo:

Intent intent = new Intent(StandardActivity.this, StandardActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

se iniciará StandardActivitycon la condición singleTop launchMode.

Hay bastantes banderas con las que puede trabajar. Puede encontrar más información sobre esto aquí .

Espero que hayas encontrado útil este artículo =)

Aprende más sobre el curso

All Articles