Étapes du cycle de vie d'une activité

1. Avant de commencer

Dans cet atelier de programmation, vous allez apprendre un élément fondamental d'Android : le cycle de vie d'une activité.

Au cours de sa "vie", une activité passe par différents états. On désigne ce changement d'états sous le nom de "cycle de vie d'une activité".

Dans Android, une activité est le point d'entrée des interactions avec l'utilisateur.

Auparavant, une activité affichait un seul écran dans une application. Avec les bonnes pratiques actuelles, une activité peut afficher plusieurs écrans en les permutant en fonction des besoins.

Le cycle de vie d'une activité s'étend de sa création à sa destruction, moment auquel le système récupère ses ressources. Lorsqu'un utilisateur change d'activité, chaque activité passe d'un état à un autre dans le cycle de vie.

En tant que développeur Android, vous devez comprendre le concept de cycle de vie d'une activité. Si les activités ne répondent pas correctement aux changements d'état de cycle de vie, l'application peut générer des bugs étranges, perturber l'expérience utilisateur ou consommer une quantité excessive de ressources système Android. Il est essentiel de comprendre le cycle de vie Android et de répondre en conséquence à chacun de ses changements d'état pour le développement sur Android.

Conditions préalables

  • Vous savez ce qu'est une activité et comment en créer une dans votre application.
  • Vous connaissez le fonctionnement de la méthode onCreate() d'une activité et le type des opérations effectuées dans cette méthode.

Points abordés

  • Impression d'informations de journalisation dans l'outil Logcat
  • Principes de base du cycle de vie de l'objet Activity et rappels appelés lorsque l'activité passe d'un état à un autre
  • Remplacement des méthodes de rappel de cycle de vie pour effectuer des opérations à différents moments du cycle de vie d'une activité

Objectifs de l'atelier

  • Modifier une application de démarrage appelée Dessert Clicker afin d'ajouter les informations de journalisation affichées dans l'outil Logcat.
  • Remplacer les méthodes de rappel de cycle de vie et consigner les modifications apportées à l'état d'une activité.
  • Exécuter l'application et observer les informations de journalisation qui s'affichent lorsque l'activité démarre, s'arrête et reprend.
  • Implémenter rememberSaveable afin de conserver les données d'application qui pourraient être perdues en cas de modification de la configuration de l'appareil.

2. Présentation de l'application

Dans cet atelier de programmation, vous utiliserez une application de démarrage appelée Dessert Clicker. Chaque fois que l'utilisateur appuie sur un dessert à l'écran, l'application "achète" le dessert. L'application met à jour, dans la mise en page, les valeurs correspondant aux éléments suivants :

  • Nombre de desserts achetés
  • Revenu total sur les desserts achetés

245d0bdfc09f4d54.png

Cette appli contient plusieurs bugs liés au cycle de vie Android. Par exemple, dans certains cas, les valeurs des desserts sont réinitialisées sur 0. Comprendre le cycle de vie Android vous aidera à comprendre pourquoi ces problèmes surviennent et comment les résoudre.

Télécharger le code de démarrage

Dans Android Studio, ouvrez le dossier basic-android-kotlin-compose-training-dessert-clicker.

3. Explorer les méthodes du cycle de vie et ajouter une journalisation de base

Chaque activité correspond à ce que l'on appelle un cycle de vie. Il s'agit d'une analogie avec le cycle de vie des plantes et des animaux, comme le cycle de vie d'un papillon : les différents états du papillon montrent sa croissance, de l'œuf à la mort, en passant par la chenille, la chrysalide et le papillon.

Cycle de vie des papillons : croissance de l'œuf à la chenille, à la chrysalide, au papillon et à la mort.

De la même façon, le cycle de vie d'une activité est constitué des différents états par lesquels une activité peut passer, de sa première initialisation à sa destruction, moment auquel le système d'exploitation (OS) récupère son espace mémoire. En règle générale, le point d'entrée d'un programme est la méthode main(). Cependant, les activités Android commencent par la méthode onCreate() qui serait l'équivalent du stade de l'œuf dans l'exemple du papillon. Comme vous avez déjà utilisé des activités à de nombreuses reprises tout au long de ce cours, il se peut que vous reconnaissiez la méthode onCreate(). Lorsque l'utilisateur lance votre application, navigue entre les activités, passe de votre application à une autre, l'état de l'activité change.

Le diagramme suivant illustre tous les états du cycle de vie d'une activité. Comme leur nom l'indique, ces états représentent le statut de l'activité. Notez que, contrairement au cycle de vie du papillon, le cycle de vie d'une activité ne s'effectue pas dans une seule direction, mais peut naviguer entre les états.

ca808edb1c95f07a.png

Il est fréquent de vouloir modifier un certain comportement ou exécuter un code spécifique lors d'un changement d'état du cycle de vie d'une activité. Par conséquent, la classe Activity proprement dite, ainsi que les sous-classes d'Activity comme ComponentActivity, implémentent un ensemble de méthodes de rappel de cycle de vie. Android appelle ces rappels lorsque l'activité passe d'un état à un autre. Vous pouvez remplacer ces méthodes dans vos propres activités afin d'effectuer des tâches en réponse à ces changements d'état du cycle de vie. Le schéma suivant illustre les états du cycle de vie et les rappels disponibles qui peuvent être remplacés.

Schéma du cycle de vie d'une activité

Il est important de savoir quand Android appelle les rappels qui peuvent être remplacés et que faire dans chaque méthode de rappel. Toutefois, ces deux diagrammes sont complexes et peuvent prêter à confusion. Dans cet atelier de programmation, au lieu de vous contenter de lire la signification de chaque état et rappel, vous ferez vos propres recherches pour mieux comprendre le cycle de vie d'une activité Android.

Étape 1 : Examinez la méthode onCreate() et ajoutez une journalisation

Pour bien comprendre le cycle de vie Android, il est utile de savoir quand les différentes méthodes de cycle de vie sont appelées. Ces informations vous aident à localiser les problèmes dans l'application Dessert Clicker.

Pour cela, une méthode simple consiste à utiliser la fonctionnalité de journalisation Android. La journalisation vous permet d'écrire de courts messages dans une console pendant l'exécution de l'application et de l'utiliser pour déterminer à quel moment les différents rappels sont déclenchés.

  1. Exécutez l'application Dessert Clicker et appuyez plusieurs fois sur la photo du dessert. Notez que la valeur de Desserts Sold (Desserts vendus) et du montant total en dollars change.
  2. Ouvrez MainActivity.kt et examinez la méthode onCreate() pour cette activité :
override fun onCreate(savedInstanceState: Bundle?) {
    // ...
}

Dans le schéma du cycle de vie de l'activité, vous avez peut-être reconnu la méthode onCreate(), car vous avez déjà utilisé ce rappel. C'est la seule méthode que chaque activité doit implémenter. La méthode onCreate() vous permet d'effectuer des initialisations ponctuelles pour votre activité. Par exemple, dans onCreate(), vous appelez setContent(), qui spécifie la mise en page d'interface utilisateur de l'activité.

Méthode onCreate Lifecycle

La méthode de cycle de vie onCreate() est appelée une seule fois, juste après l'initialisation de l'activité, lorsque le système d'exploitation crée l'objet Activity en mémoire. Une fois que onCreate() a été exécuté, l'activité est considérée comme créée.

  1. Ajoutez la constante suivante au niveau supérieur de MainActivity.kt, au-dessus de la déclaration de classe class MainActivity.

Il est recommandé de déclarer une constante TAG dans votre fichier, car sa valeur ne change pas.

Pour la marquer comme constante au moment de la compilation (compile-time), utilisez const lors de la déclaration de la variable. Une constante de ce type est une valeur qui est connue au cours de la compilation.

private const val TAG = "MainActivity"
  1. Dans la méthode onCreate(), juste après l'appel de super.onCreate(), ajoutez la ligne suivante :
Log.d(TAG, "onCreate Called")
  1. Importez la classe Log si nécessaire (appuyez sur Alt+Enter, ou Option+Enter sur Mac, puis sélectionnez Importer). Si vous avez activé l'importation automatique, l'opération devrait avoir lieu automatiquement.
import android.util.Log

La classe Log écrit les messages dans l'outil Logcat. Logcat est la console de journalisation des messages. C'est là que les messages Android concernant votre application s'affichent, y compris ceux que vous envoyez explicitement au journal avec la méthode Log.d() ou d'autres méthodes de classe Log.

L'instruction Log repose sur trois aspects importants :

  • La priorité du message de journal, c'est-à-dire son importance. Dans ce cas, Log.v() consigne des messages détaillés. La méthode Log.d() écrit un message de débogage. Les autres méthodes de la classe Log incluent Log.i() pour les messages d'information, Log.w() pour les avertissements et Log.e() pour les messages d'erreur.
  • La tag de journal (premier paramètre), dans ce cas "MainActivity". La balise est une chaîne qui vous permet de trouver plus facilement vos messages de journal dans Logcat. Elle correspond généralement au nom de la classe.
  • Le message de journal proprement dit, appelé msg (deuxième paramètre), est une chaîne courte qui, dans ce cas, est "onCreate Called".

a4ff4aa74384ff6.png

  1. Compilez et exécutez l'application Dessert Clicker. Vous ne constaterez aucune différence de comportement dans l'application lorsque vous appuierez sur le dessert. Dans Android Studio, cliquez sur l'onglet Logcat en bas de l'écran.

cedcce52592c6665.png

  1. Dans la fenêtre Logcat, saisissez tag:MainActivity dans le champ de recherche.

37080c4e00561b0.png

Logcat peut contenir de nombreux messages, dont la plupart ne vous sont pas utiles. Vous pouvez filtrer les entrées Logcat de différentes manières, mais la recherche est la méthode la plus simple. Étant donné que vous avez utilisé MainActivity comme balise de journal dans le code, vous pouvez l'utiliser pour filtrer le journal. Votre message de journal comprend la date et l'heure, votre balise de journal, le nom du package (com.example.dessertclicker) et le message proprement dit. Comme ce message apparaît dans le journal, vous savez que onCreate() a été exécuté.

Étape 2 : Implémentez la méthode onStart()

La méthode de cycle de vie onStart() est appelée juste après onCreate(). Une fois que onStart() a été exécuté, l'activité est visible à l'écran. Contrairement à onCreate(), qui n'est appelé qu'une seule fois pour initialiser votre activité, onStart() peut être appelé plusieurs fois par le système au cours du cycle de vie de l'activité.

a357d2291de472d9.png

Notez que la méthode onStart() est associée à une méthode de cycle de vie onStop() correspondante. Si l'utilisateur lance votre application, puis revient à l'écran d'accueil de l'appareil, l'activité est interrompue et n'est plus visible à l'écran.

  1. Dans Android Studio, lorsque MainActivity.kt est ouvert et que le curseur se trouve dans la classe MainActivity, sélectionnez Code > Remplacer les méthodes ou appuyez sur Control+O. Une boîte de dialogue s'affiche avec une longue liste répertoriant toutes les méthodes que vous pouvez remplacer dans cette classe.

20c34cbad8dce892.png

  1. Commencez à saisir onStart pour rechercher la méthode appropriée. Pour accéder à l'élément correspondant suivant, utilisez la flèche vers le bas. Sélectionnez onStart() dans la liste, puis cliquez sur OK pour insérer le code de remplacement réutilisable. Le code se présente comme suit :
override fun onStart() {
    super.onStart()
}
  1. Dans la méthode onStart(), ajoutez un message de journal :
override fun onStart() {
    super.onStart()
    Log.d(TAG, "onStart Called")
}
  1. Compilez et exécutez l'application Dessert Clicker, puis ouvrez le volet Logcat.
  2. Saisissez tag:MainActivity dans le champ de recherche pour filtrer le journal. Notez que les méthodes onCreate() et onStart() ont été appelées l'une après l'autre, et que votre activité est visible à l'écran.
  3. Appuyez sur le bouton Accueil de l'appareil, puis utilisez l'écran "Actions récentes" pour revenir à l'activité. Notez que l'activité reprend là où elle s'était arrêtée, avec les mêmes valeurs, et que la méthode onStart() est consignée une deuxième fois dans Logcat. Notez également que la méthode onCreate() n'est pas rappelée.
2024-04-26 14:54:48.721  5386-5386  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-04-26 14:54:48.756  5386-5386  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 14:55:41.674  5386-5386  MainActivity            com.example.dessertclicker           D  onStart Called

Étape 3 : Ajoutez d'autres instructions de journalisation

Au cours de cette étape, vous implémenterez la journalisation pour toutes les autres méthodes de cycle de vie.

  1. Remplacez les autres méthodes du cycle de vie dans MainActivity et ajoutez des instructions de journalisation pour chacune d'elles, comme indiqué dans le code ci-dessous :
override fun onResume() {
    super.onResume()
    Log.d(TAG, "onResume Called")
}

override fun onRestart() {
    super.onRestart()
    Log.d(TAG, "onRestart Called")
}

override fun onPause() {
    super.onPause()
    Log.d(TAG, "onPause Called")
}

override fun onStop() {
    super.onStop()
    Log.d(TAG, "onStop Called")
}

override fun onDestroy() {
    super.onDestroy()
    Log.d(TAG, "onDestroy Called")
}
  1. Compilez et exécutez à nouveau Dessert Clicker, puis examinez Logcat.

Cette fois, vous remarquerez qu'en plus des méthodes onCreate() et onStart(), il existe un message de journal pour le rappel du cycle de vie onResume().

2024-04-26 14:56:48.684  5484-5484  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-04-26 14:56:48.709  5484-5484  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 14:56:48.713  5484-5484  MainActivity            com.example.dessertclicker           D  onResume Called

Lorsqu'une activité commence au début, les trois rappels de cycle de vie suivants sont appelés dans l'ordre :

  • onCreate() lorsque le système crée l'application.
  • onStart() rend l'application visible à l'écran, mais aucune interaction de l'utilisateur n'est encore possible.
  • onResume() affiche l'application au premier plan et l'utilisateur peut maintenant interagir.

Malgré son nom, la méthode onResume() est appelée au démarrage, même s'il n'y a rien à reprendre.

Schéma du cycle de vie d'une activité

4. Explorer quelques cas d'utilisation du cycle de vie

Maintenant que vous avez configuré l'application Dessert Clicker pour la journalisation, vous êtes prêt à l'utiliser et à découvrir comment les rappels de cycle de vie sont déclenchés.

Cas d'utilisation 1 : Ouvrir et fermer l'activité

Commencez par le cas d'utilisation le plus basique, qui consiste à démarrer l'application pour la première fois, puis à la fermer.

  1. Compilez et exécutez l'application Dessert Clicker, si elle n'est pas déjà en cours d'exécution. Comme vous l'avez vu, les rappels onCreate(), onStart() et onResume() sont appelés lorsque l'activité démarre pour la première fois.
2024-04-26 14:56:48.684  5484-5484  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-04-26 14:56:48.709  5484-5484  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 14:56:48.713  5484-5484  MainActivity            com.example.dessertclicker           D  onResume Called
  1. Appuyez plusieurs fois sur le cupcake.
  2. Appuyez sur le bouton Retour de l'appareil.

Notez que dans Logcat, onPause() et onStop() sont appelés dans cet ordre.

2024-04-26 14:58:19.984  5484-5484  MainActivity            com.example.dessertclicker           D  onPause Called
2024-04-26 14:58:20.491  5484-5484  MainActivity            com.example.dessertclicker           D  onStop Called
2024-04-26 14:58:20.517  5484-5484  MainActivity            com.example.dessertclicker           D  onDestroy Called

Dans ce cas, si vous utilisez le bouton Retour, l'activité (et l'application) est supprimée de l'écran et déplacée à l'arrière de la pile d'activités.

Il se peut que l'OS Android ferme votre activité si votre code appelle manuellement la méthode finish() de l'activité ou si l'utilisateur force l'arrêt de l'application. Par exemple, l'utilisateur peut forcer l'arrêt de l'application ou la fermer dans l'écran "Actions récentes". L'OS peut également arrêter lui-même votre activité si votre application n'a plus été affichée à l'écran depuis longtemps. Android procède de la sorte pour préserver l'autonomie de la batterie et pour permettre à d'autres applications d'utiliser les ressources de votre application. Ce ne sont là que quelques exemples des raisons qui poussent le système Android à détruire votre activité. Dans certains cas, il se peut que le système Android détruise votre activité sans fournir le moindre avertissement.

Cas d'utilisation 2 : Quitter l'activité et y revenir

Maintenant que vous avez lancé et fermé l'application, vous avez vu la plupart des états du cycle de vie lorsque l'activité est créée pour la première fois. Vous avez également vu la plupart des états du cycle de vie que traverse une activité lorsqu'elle est fermée. Toutefois, lorsque les utilisateurs interagissent avec leur appareil Android, ils passent d'une application à l'autre, reviennent à l'écran d'accueil, lancent de nouvelles applications et doivent gérer les interruptions liées à d'autres activités, comme les appels téléphoniques.

Votre activité ne se ferme pas complètement chaque fois que l'utilisateur la quitte :

  • Lorsque votre activité n'est plus visible à l'écran, on parle d'activité en arrière-plan. À l'inverse, on parle d'activité au premier plan ou à l'écran.
  • Lorsque l'utilisateur revient dans votre application, la même activité est redémarrée et redevient visible. Cette partie est appelée cycle de vie visible de l'application.

Lorsque l'application est exécutée en arrière-plan, elle ne doit généralement pas être exécutée activement pour préserver les ressources système et l'autonomie de la batterie. Le cycle de vie et les rappels de l'élément Activity vous permettent de savoir quand l'application passe en arrière-plan afin de pouvoir suspendre les opérations en cours. Vous relancez ensuite les opérations lorsque l'application est exécutée au premier plan.

Au cours de cette étape, vous allez examiner le cycle de vie de l'activité lorsque l'application passe en arrière-plan, puis revient au premier plan.

  1. Une fois l'application Dessert Clicker en cours d'exécution, cliquez plusieurs fois sur le cupcake.
  2. Appuyez sur le bouton Accueil de votre appareil et observez l'outil Logcat dans Android Studio. Lorsque vous revenez à l'écran d'accueil, votre application est mise en arrière-plan au lieu de s'arrêter complètement. Notez que les méthodes onPause() et onStop() sont appelées.
2024-04-26 15:00:04.905  5590-5590  MainActivity            com.example.dessertclicker           D  onPause Called
2024-04-26 15:00:05.430  5590-5590  MainActivity            com.example.dessertclicker           D  onStop Called

Lorsque la méthode onPause() est appelée, l'application n'est plus active. Après onStop(), l'application n'est plus visible à l'écran. Bien que l'activité ait été arrêtée, l'objet Activity est toujours en mémoire, en arrière-plan. L'OS Android n'a pas détruit l'activité. L'utilisateur peut revenir à l'application. Android conserve donc vos ressources d'activité.

c470ee28ab7f8a1a.png

  1. Utilisez l'écran "Actions récentes" pour revenir à l'application. Sur l'émulateur, vous pouvez accéder à cet écran à l'aide du bouton carré indiqué dans l'image ci-dessous.

Notez que dans Logcat, l'activité est redémarrée avec onRestart() et onStart(), puis reprise avec onResume().

bc156252d977e5ae.png

2024-04-26 15:00:39.371  5590-5590  MainActivity            com.example.dessertclicker           D  onRestart Called
2024-04-26 15:00:39.372  5590-5590  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 15:00:39.374  5590-5590  MainActivity            com.example.dessertclicker           D  onResume Called

Lorsque l'activité revient au premier plan, la méthode onCreate() n'est pas rappelée. L'objet d'activité n'a pas été détruit. Il n'a donc pas besoin d'être créé à nouveau. Au lieu d'onCreate(), la méthode onRestart() est maintenant appelée. Notez que cette fois, lorsque l'activité revient au premier plan, le nombre de desserts vendus (Desserts sold) est conservé.

  1. Lancez au moins une application autre que Dessert Clicker afin que l'écran "Actions récentes" de l'appareil affiche quelques applications.
  2. Affichez l'écran "Actions récentes" et ouvrez une autre activité récente. Revenez ensuite aux applications récentes et remettez Dessert Clicker au premier plan.

Notez que les mêmes rappels s'affichent dans Logcat lorsque vous appuyez sur le bouton Accueil. onPause() et onStop() sont appelés lorsque l'application passe en arrière-plan. onRestart(), onStart() et onResume() sont ensuite appelés lorsqu'elle revient au premier plan.

Ces méthodes sont appelées lorsque l'application s'arrête et qu'elle passe en arrière-plan, ou lorsqu'elle redémarre et qu'elle revient au premier plan. Si vous devez effectuer une tâche dans votre application dans ces situations, remplacez la méthode de rappel de cycle de vie appropriée.

Cas d'utilisation 3 : Masquer partiellement l'activité

Vous avez vu que lorsqu'une application est démarrée et que la méthode onStart() est appelée, l'application devient visible à l'écran. Lorsque la méthode onResume() est appelée, l'application reçoit le focus de l'utilisateur, ce qui signifie que l'utilisateur peut interagir avec elle. La partie du cycle de vie dans laquelle l'application est entièrement affichée à l'écran et a le focus de l'utilisateur est appelée durée de vie au premier plan.

Lorsque l'application passe en arrière-plan, le focus est perdu après onPause(), et l'application n'est plus visible après onStop().

Il est important de faire la différence entre focus et visibilité. En effet, il est possible qu'une activité soit partiellement visible à l'écran, sans qu'elle n'ait le focus de l'utilisateur. Au cours de cette étape, vous allez examiner un cas où une activité est partiellement visible, sans avoir le focus de l'utilisateur.

  1. Une fois l'application Dessert Clicker en cours d'exécution, cliquez sur le bouton Partager dans l'angle supérieur droit de l'écran.

L'activité de partage apparaît dans la moitié inférieure de l'écran, mais votre activité reste visible dans la moitié supérieure.

677c190d94e57447.pngca6285cbbe3801cf.png

  1. Examinez Logcat et notez que seul onPause() a été appelé.
2024-04-26 15:01:49.535  5590-5590  MainActivity            com.example.dessertclicker           D  onPause Called

Dans ce cas d'utilisation, onStop() n'est pas appelé, car l'activité est encore partiellement visible. Toutefois, l'activité ne reçoit pas le focus de l'utilisateur. Celui-ci ne peut donc pas interagir avec elle. L'activité de partage qui est au premier plan reçoit le focus de l'utilisateur.

Pourquoi cette différence est-elle importante ? L'interruption avec onPause() uniquement dure peu de temps avant de revenir à votre activité ou d'accéder à une autre activité ou application. Il est généralement conseillé de continuer à mettre à jour l'interface utilisateur pour que le reste de votre application ne semble pas se figer.

Le code exécuté dans onPause() empêche l'affichage d'autres éléments. Par conséquent, n'abusez pas de l'utilisation de l'élément onPause(). Par exemple, si un appel téléphonique arrive, le code dans onPause() peut retarder la notification de l'appel entrant.

  1. Cliquez en dehors de la boîte de dialogue de partage pour revenir à l'application. Vous remarquerez que l'élément onResume() est appelé.

onResume() et onPause() sont tous deux liés au focus. La méthode onResume() est appelée lorsque l'activité reçoit le focus de l'utilisateur, tandis que la méthode onPause() est appelée lorsque l'activité le perd.

5. Explorer les modifications de la configuration

Il est important de connaître un autre cas de figure dans la gestion du cycle de vie d'une activité : l'impact des modifications de la configuration sur le cycle de vie de vos activités.

Une modification de la configuration se produit lorsque l'état de l'appareil change de manière si radicale que le moyen le plus simple de s'adapter à cette modification consiste à arrêter complètement l'activité et à la recréer. Par exemple, si l'utilisateur change la langue de l'appareil, la mise en page devra peut-être changer pour s'adapter aux différentes orientations de texte et longueurs de chaîne. Si l'utilisateur branche l'appareil sur une station d'accueil ou ajoute un clavier physique, l'application devra peut-être s'ajuster à un changement de taille d'écran ou de mise en page. Si l'orientation de l'appareil change (s'il passe du mode Portrait au mode Paysage, ou inversement), il se peut que la mise en page doive être modifiée pour s'adapter à la nouvelle orientation. Voyons le comportement de l'application dans ce scénario.

Le dernier rappel de cycle de vie à démontrer est onDestroy(), qui est appelé après onStop(). Il est appelé juste avant la destruction de l'activité. Cela peut se produire lorsque le code de l'application appelle finish() ou lorsque le système doit détruire et recréer l'activité en raison d'une modification de la configuration.

Une modification de la configuration entraîne l'appel de onDestroy()

La rotation d'écran est un type de modification de la configuration qui entraîne l'arrêt et le redémarrage de l'activité. Pour simuler cette modification de configuration et examiner ses effets, procédez comme suit :

  1. Compilez et exécutez votre application.
  2. Assurez-vous que le verrouillage de la rotation de l'écran est désactivé dans l'émulateur.
  3. Faites pivoter l'appareil ou l'émulateur en mode Paysage. Vous pouvez faire pivoter l'émulateur vers la gauche ou vers la droite à l'aide des boutons de rotation.
  4. Examinez Logcat. Vous constatez que lorsque l'activité s'arrête, elle appelle onPause(), onStop() et onDestroy(), dans cet ordre.
2024-04-26 15:03:32.183  5716-5716  MainActivity            com.example.dessertclicker           D  onPause Called
2024-04-26 15:03:32.185  5716-5716  MainActivity            com.example.dessertclicker           D  onStop Called
2024-04-26 15:03:32.205  5716-5716  MainActivity            com.example.dessertclicker           D  onDestroy Called

Perte de données lors de la rotation de l'appareil

  1. Compilez et exécutez votre application, puis ouvrez Logcat.
  2. Cliquez plusieurs fois sur le cupcake, et notez que les desserts vendus et le total des revenus ne sont pas nuls.
  3. Assurez-vous que le verrouillage de la rotation de l'écran est désactivé dans l'émulateur.
  4. Faites pivoter l'appareil ou l'émulateur en mode Paysage. Vous pouvez faire pivoter l'émulateur vers la gauche ou vers la droite à l'aide des boutons de rotation.

11c9d83a11651608.png

  1. Examinez la sortie dans Logcat. Filtrez la sortie sur MainActivity.
2024-04-26 15:04:29.356  5809-5809  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-04-26 15:04:29.378  5809-5809  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 15:04:29.382  5809-5809  MainActivity            com.example.dessertclicker           D  onResume Called
2024-04-26 15:06:52.168  5809-5809  MainActivity            com.example.dessertclicker           D  onPause Called
2024-04-26 15:06:52.183  5809-5809  MainActivity            com.example.dessertclicker           D  onStop Called
2024-04-26 15:06:52.219  5809-5809  MainActivity            com.example.dessertclicker           D  onDestroy Called
2024-04-26 15:06:52.302  5809-5809  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-04-26 15:06:52.308  5809-5809  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 15:06:52.312  5809-5809  MainActivity            com.example.dessertclicker           D  onResume Called

Notez que lorsque l'appareil ou l'émulateur fait pivoter l'écran, le système appelle tous les rappels de cycle de vie afin d'arrêter l'activité. Ensuite, lorsque l'activité est recréée, le système appelle tous les rappels de cycle de vie pour la démarrer.

Lors de la rotation de l'appareil, et lorsque l'activité est arrêtée et recréée, celle-ci redémarre avec des valeurs par défaut : l'image du dessert, le nombre de desserts vendus et le total des revenus sont remis à zéro.

Pour comprendre pourquoi ces valeurs sont réinitialisées et comment les corriger, vous devez en savoir plus sur le cycle de vie d'un composable, et comprendre comment il observe et maintient son état.

Cycle de vie d'un composable

Au départ, l'interface utilisateur de votre application est conçue à partir de fonctions modulables en cours d'exécution, selon un processus appelé "Composition".

Une recomposition est planifiée lorsque l'état de l'application change. On parle de recomposition lorsque Compose exécute à nouveau les fonctions composables dont l'état a peut-être changé et crée une interface utilisateur mise à jour. La composition est mise à jour pour tenir compte de ces modifications.

La seule façon de créer ou de mettre à jour une composition consiste à passer par sa composition initiale et les recompositions ultérieures.

Les fonctions modulables ont leur propre cycle de vie, qui est indépendant de celui de l'activité. Son cycle de vie est constitué des événements suivants : accéder à la composition, exécuter zéro ou plusieurs recompositions, puis quitter la composition.

Pour que Compose puisse suivre et déclencher une recomposition, il doit savoir à quel moment l'état a changé. Pour indiquer à Compose qu'il doit suivre l'état d'un objet, celui-ci doit être de type State ou MutableState. Le type State est immuable et peut seulement être lu. Un type MutableState est modifiable, et autorise les lectures et les écritures.

Vous avez déjà découvert et utilisé le type MutableState dans l'application Lemonade et l'application Tip Time lors d'ateliers de programmation précédents.

Pour créer la variable modifiable revenue, vous la déclarez à l'aide de mutableStateOf. 0 est sa valeur par défaut initiale.

var revenue = mutableStateOf(0)

Cela suffit pour que Compose déclenche une recomposition lorsque la valeur des revenus change, mais cela s'avère insuffisant pour conserver sa valeur mise à jour. Chaque fois que le composable est réexécuté, la valeur des revenus par défaut est réinitialisée (0).

Pour indiquer à Compose de conserver et de réutiliser sa valeur lors des recompositions, vous devez le déclarer avec l'API remember.

var revenue by remember { mutableStateOf(0) }

Si la valeur de revenue change, Compose planifie toutes les fonctions modulables qui la lisent pour la recomposition.

Bien que Compose mémorise l'état des revenus lors des recompositions, il ne le conserve pas lors d'une modification de configuration. Pour que Compose conserve l'état lors d'un changement de configuration, vous devez utiliser rememberSaveable.

Pour accéder à des informations et à des exercices supplémentaires, reportez-vous à l'atelier de programmation intitulé Présentation de l'état dans Compose.

Utiliser rememberSaveable pour enregistrer les valeurs lors des modifications de configuration

La fonction rememberSaveable vous permet d'enregistrer les valeurs dont vous avez besoin lorsque l'OS Android détruit et recrée l'activité.

Pour enregistrer des valeurs lors des recompositions, vous devez utiliser remember. Utilisez rememberSaveable pour enregistrer les valeurs à la fois lors des recompositions et des changements de configuration.

Enregistrer la valeur à l'aide de rememberSaveable permet de s'assurer qu'elle est disponible lorsque l'activité est restaurée, si nécessaire.

  1. Dans MainActivity, mettez à jour le groupe de cinq variables qui utilisent actuellement remember sur rememberSaveable.
var revenue by remember { mutableStateOf(0) }
...
var currentDessertImageId by remember {
    mutableStateOf(desserts[currentDessertIndex].imageId)
}
var revenue by rememberSaveable { mutableStateOf(0) }
...
var currentDessertImageId by rememberSaveable {
    mutableStateOf(desserts[currentDessertIndex].imageId)
}
  1. Compilez et exécutez votre application.
  2. Cliquez plusieurs fois sur le cupcake, et notez que les desserts vendus et le total des revenus ne sont pas nuls.
  3. Faites pivoter l'appareil ou l'émulateur en mode Paysage.
  4. Une fois l'activité détruite et recréée, l'image du dessert, les desserts vendus et le total des revenus sont restaurés sur leurs valeurs antérieures.

6. Code de solution

7. Résumé

Cycle de vie d'une activité

  • Le cycle de vie d'une activité correspond à un ensemble d'états par lesquels passe une activité. Il commence lorsque l'OS Android crée l'activité et se termine lorsque l'OS la détruit.
  • Lorsque l'utilisateur passe d'une activité à une autre, et de votre application à une autre, l'état change dans le cycle de vie de l'activité.
  • Chaque état du cycle de vie de l'activité possède une méthode de rappel correspondante que vous pouvez remplacer dans la classe Activity. Les principales méthodes de cycle de vie sont les suivantes : onCreate(), onRestart(), onStart(), onResume(), onPause(), onStop(), onDestroy().
  • Pour ajouter le comportement qui se produit lorsque votre activité passe à un état du cycle de vie, remplacez la méthode de rappel correspondante.
  • Pour ajouter des méthodes de remplacement à vos classes dans Android Studio, sélectionnez Code > Remplacer les méthodes ou appuyez sur Control+O.

Journalisation

  • L'API de journalisation Android, et plus particulièrement la classe Log, vous permet d'écrire des messages courts affichés dans l'outil Logcat dans Android Studio.
  • Utilisez Log.d() pour rédiger un message de débogage. Cette méthode utilise deux arguments : la balise de journal (généralement un nom de classe) et le message de journal (une courte chaîne).
  • Utilisez la fenêtre Logcat d'Android Studio pour afficher les journaux système, y compris les messages que vous écrivez.

Modifications de la configuration

  • Une modification de la configuration se produit lorsque l'état de l'appareil change de manière si radicale que le moyen le plus simple de s'adapter à cette modification consiste à détruire l'activité et à la recréer.
  • L'exemple le plus courant de modification de la configuration est lorsque l'utilisateur fait pivoter l'appareil du mode Portrait au mode Paysage, ou inversement. Une modification de la configuration peut également se produire lorsque la langue de l'appareil change ou qu'un utilisateur branche un clavier matériel.
  • Lorsqu'une modification de configuration se produit, Android appelle tous les rappels d'arrêt du cycle de vie de l'activité. Android redémarre ensuite l'activité à partir de zéro, en exécutant tous les rappels de démarrage du cycle de vie.
  • Quand Android arrête une application en raison d'une modification de la configuration, il redémarre l'activité avec onCreate().
  • Pour enregistrer une valeur qui doit survivre à une modification de configuration, déclarez ses variables avec rememberSaveable.

En savoir plus