Avant l’API 11, nous avions l’habitude que les activités montrent chaque nouvelle page à l’écran. Maintenant, avec les fragments et les outils de navigation de l’API 28, il est tout à fait possible de créer une application très complexe avec une seule activité. Cependant, les activités sont toujours très utiles pour diviser votre application en étapes et en processus. Vous pouvez par exemple diviser le marketing en une seule activité et placer l’application elle-même dans sa propre activité. Vous souhaitez peut-être qu’une section soit réservée à une fonctionnalité, comme un service de chat. Connaître les modes de lancement des activités vous aide à mieux diviser ces processus de manière à ce qu’ils aient un sens pour vos utilisateurs. Assis au travail, je ne pourrais jamais me souvenir des modes de lancement de tête, alors j’ai pensé écrire un blog à ce sujet, animer quelques gifs pour illustrer les concepts, puis le partager avec tout le monde. Enjoy!
Avant de parler des modes de lancement, comprenons d’abord le rôle d’une tâche. Une tâche contient une collection d’activités qui sont disposées dans une pile appelée le backstack. La première activité à être lancée dans une tâche est l’activité racine. Appuyer sur le bouton retour d’une activité racine ne tue pas seulement l’activité, mais aussi la tâche, et éventuellement l’application.
Maintenant, plongeons dans quelques modes de lancement !
Disons que vous avez une tâche avec une activité racine appelée Activité A, puis lancez une nouvelle activité appelée B, B est poussée au sommet de la pile. Maintenant, disons que vous lancez une autre activité B à partir du B que nous venons de créer, vous aurez maintenant deux instances de l’activité B empilées l’une sur l’autre. Si un utilisateur appuie sur le bouton retour, il retournera à une autre instance de l’Activité B. Cela peut être très déroutant pour l’utilisateur. L’empilement et la création d’activités les unes sur les autres, quoi qu’il arrive, est appelé le mode de lancement standard. Si aucun mode de lancement n’est défini dans le XML de l’activité dans le manifeste, l’activité utilisera le mode de lancement standard.
Maintenant que nous voyons comment le mode Standard peut être déstabilisant pour l’utilisateur, nous pouvons maintenant comprendre le mode de lancement Single Top. Ce mode de lancement empêche les différentes instances des mêmes activités d’être empilées les unes sur les autres. Disons que l’activité B est une activité unique. Nous pouvons définir les modes de lancement dans le manifeste comme suit :
///AndroidManifest.xml
<application
...>
<activity android:name=".Activity_A">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <activity android:name=".Activity_B" android:launchMode="singleTop"/> <activity android:name=".Activity_C"/>
<activity android:name=".Activity_D"/>
</application>
Alors maintenant, si vous lancez l’activité B à partir de l’activité B, au lieu de créer une nouvelle instance de B et de l’empiler sur l’ancienne B, l’intention est transmise dans l’instance actuelle de B. La seule façon d’avoir deux instances de la même activité dans une tâche est de lancer une activité différente à partir de B, puis de créer B à partir de cette activité. Le concept principal du mode de lancement unique supérieur est que vous ne pouvez pas avoir deux instances de la même activité empilées l’une sur l’autre.
Si vous ne voulez pas 2 instances de la même activité unique supérieure dans une tâche tout en utilisant le mode de lancement unique supérieur, vous pouvez passer la constante FLAG_ACTIVITY_CLEAR_TOP dans votre intention. Pour illustrer ce que cela fait, disons que votre pile d’activités est ABC (B est toujours en tête de liste). Si vous lancez B à partir de C avec FLAG_ACTIVITY_CLEAR_TOP, votre pile va sauter jusqu’à B et l’intention sera transmise à cette même instance de B.
// code example for passing the constant flag in your intentIntent intent = new Intent(this, Activity_B.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
Le mode de lancement suivant est appelé tâche unique. Dans ce mode de lancement, nous déclarons qu’une activité ne peut appartenir qu’à une seule tâche parmi toutes les tâches de l’application. Donc, de manière similaire au comportement FLAG_ACTIVITY_CLEAR_TOP, si votre pile est ABC, et que vous lancez B (une tâche unique) à partir de C, nous faisons un pop jusqu’à B, et passons l’intention à cette instance.
<activity android:name=".Activity_B" android:launchMode="singleTask"/>
Mais que faire si nous voulons que B soit dans sa propre tâche ? C’est là que l’affinité de tâches entre en jeu. L’affinité de tâche vous permet de définir à quelle tâche une activité appartient. Par défaut, une activité a la même affinité de tâche que son activité racine. Avec l’affinité de tâche, nous pouvons maintenant séparer les activités en différentes tâches.
<activity android:name=".Activity_A"
android:taskAffinity="com.affinity.of.a">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity><activity android:name=".Activity_B"
android:launchMode="singleTask"
android:taskAffinity="com.affinity.of.b"
/>
Ici, l’activité A et l’activité B ont des affinités de tâches différentes. Lorsque A est créée dans la tâche 1, C est lancée depuis A. Par défaut, chaque activité a la même affinité que sa racine, donc nous sommes toujours dans la tâche 1. Maintenant, B est lancé à partir de C. B a une affinité de tâche différente, il est donc maintenant la racine de la tâche 2, qui passe alors au premier plan. Si nous lançons une nouvelle instance de l’activité C à partir de B, C appartient à la tâche 2 car c’est l’affinité de tâche de l’activité racine (dans ce cas, B). Mais que se passe-t-il si nous essayons maintenant de lancer A à partir de C dans la tâche 2 ? Puisque l’affinité de A est la tâche 1, nous passons de la tâche 2 à la tâche 1, pop tout le chemin du retour à l’activité A, et enfin passer l’intention à A.
Connaître la tâche unique nous aidera à mieux comprendre le mode de lancement final ; l’instance unique. Comme la tâche unique, une activité avec une instance unique peut être la seule activité de toutes les tâches. La différence entre les deux est qu’une Activité avec Single Instance peut également être la seule activité dans une tâche.
<activity android:name=".Activity_B"
android:launchMode="singleInstance"
android:taskAffinity="com.affinity.of.b"
/>
Dans cet exemple, l’Activité B aura un mode de lancement de Single Instance. L’activité A de la tâche 1 lance l’activité B. Cela fait que l’activité B se lance dans une nouvelle tâche, qui est ensuite mise au premier plan. L’activité B lance ensuite l’activité C. Puisqu’une instance unique peut être la seule activité d’une tâche, C est lancée au-dessus de l’activité A dans la tâche 1, puis la tâche 1 passe au premier plan.
L’affinité de tâche joue également un rôle dans l’instance unique. Si l’activité B n’a pas d’affinité de tâche, un utilisateur ne peut pas naviguer de nouveau vers la tâche 1. Si B avait une affinité de tâche, un utilisateur pourra aller et venir entre la tâche 1 et 2.
Connaître les modes de lancement m’aide à faire de meilleures expériences UI/UX pour mes utilisateurs, et m’aide même à résoudre certains bugs qui me prennent la tête, alors j’espère que cette information vous aidera aussi !
Je veux donner un coup de chapeau à la page youtube CodeTutor d’Anil Deshpande pour m’avoir aidé à mieux comprendre le concept. Voici la première de sept vidéos sur ce sujet : https://www.youtube.com/watch?v=m8sf0UkJkxo