Cet atelier de programmation fait partie du cours Android Kotlin Fundamentals. Vous tirerez le meilleur parti de ce cours si vous suivez les ateliers de programmation dans l'ordre. Tous les ateliers de programmation du cours sont répertoriés sur la page de destination des ateliers de programmation Android Kotlin Fundamentals.
Présentation
Dans le dernier atelier de programmation, vous avez découvert les cycles de vie Activity
et Fragment
, et vous avez exploré les méthodes appelées lorsque l'état du cycle de vie change dans les activités et les fragments. Dans cet atelier de programmation, vous allez explorer le cycle de vie de l'activité plus en détail. Vous découvrirez également la bibliothèque de cycle de vie d'Android Jetpack, qui vous aide à gérer les événements de cycle de vie grâce à du code mieux organisé et plus facile à gérer.
Ce que vous devez déjà savoir
- Qu'est-ce qu'une activité et comment en créer dans votre application.
- Principes de base des cycles de vie
Activity
etFragment
, et rappels qui sont appelés lorsqu'une activité passe d'un état à un autre. - Comment remplacer les méthodes de rappel du cycle de vie
onCreate()
etonStop()
pour effectuer des opérations à des moments différents de l'activité ou du cycle de vie du fragment
Points abordés
- Configurer, démarrer et arrêter des parties de votre application dans les rappels de cycle de vie
- Utiliser la bibliothèque de cycle de vie Android pour créer un observateur de cycle de vie et faciliter la gestion de l'activité et des fragments de cycle de vie
- Incidence des coupures d'Android sur les données de votre application, et procédure d'enregistrement et de restauration automatique de ces données lorsque Android ferme votre application
- Comment la rotation des appareils et d'autres modifications de configuration modifient l'état du cycle de vie et ont une incidence sur l'état de votre application
Objectifs de l'atelier
- Modifiez l'application DessertClicker de manière à inclure une fonction de minuteur, et démarrez et arrêtez ce minuteur à différents moments du cycle de vie de l'activité.
- Modifiez l'application pour qu'elle utilise la bibliothèque Cycle de vie Android et convertissez la classe
DessertTimer
en observateur de cycle de vie. - Configurez et utilisez Android Debug Bridge (
adb
) pour simuler l'arrêt du processus et les rappels de cycle de vie qui se produisent ensuite. - Implémentez la méthode
onSaveInstanceState()
pour conserver les données d'application qui seront perdues si l'application est fermée de manière inattendue. Ajoutez un code pour restaurer ces données au redémarrage de l'application.
Dans cet atelier de programmation, vous allez développer l'application DessertClicker de l'atelier de programmation précédent. Vous ajoutez un minuteur en arrière-plan, puis vous convertissez l'application afin d'utiliser la bibliothèque de cycle de vie Android.
Dans l'atelier de programmation précédent, vous avez appris à observer l'activité et les cycles de vie des fragments en ignorant divers rappels de cycle de vie et en enregistrant lorsque le système les appelle. Dans cette tâche, vous allez découvrir un exemple plus complexe de gestion des tâches de cycle de vie dans l'application DessertClicker. Vous allez utiliser un minuteur qui affiche une instruction de journal toutes les secondes et le nombre de secondes d'exécution.
Étape 1: Configurez des desserts
- Ouvrez l'application DessertClicker du dernier atelier de programmation. (Vous pouvez télécharger DessertClickerLogs ici si vous ne disposez pas de l'application.)
- Dans la vue Projet, développez java > com.example.android.dessertclicker et ouvrez
DessertTimer.kt
. Notez que, pour le moment, l'ensemble du code est commenté, et il ne s'exécute donc pas dans l'application. - Sélectionnez tout le code dans la fenêtre de l'éditeur. Sélectionnez Code > Commenter avec un commentaire au trait ou appuyez sur
Control+/
(Command+/
sur un Mac). Cette commande annule la mise en commentaire de l'ensemble du code du fichier. Il est possible qu'Android Studio affiche des erreurs de référence non résolues jusqu'à ce que vous recréez l'application. - Notez que la classe
DessertTimer
inclutstartTimer()
etstopTimer()
, qui démarrent et arrêtent le minuteur. LorsquestartTimer()
est en cours d'exécution, le minuteur affiche un message de journal toutes les secondes, avec le nombre total de secondes d'exécution. À son tour, la méthodestopTimer()
arrête le minuteur et les instructions de journalisation.
- Ouvrez
MainActivity.kt
. En haut de la classe, juste en dessous de la variabledessertsSold
, ajoutez une variable pour le minuteur :
private lateinit var dessertTimer : DessertTimer;
- Faites défiler la page jusqu'à
onCreate()
et créez un objetDessertTimer
, juste après l'appel desetOnClickListener()
:
dessertTimer = DessertTimer()
Maintenant que vous disposez d'un objet de minuteur, envisagez de démarrer et d'arrêter le minuteur pour qu'il ne s'exécute que lorsque l'activité s'affiche à l'écran. Vous allez examiner plusieurs options lors des prochaines étapes.
Étape 2: Lancez et arrêtez le minuteur
La méthode onStart()
est appelée juste avant que l'activité ne soit visible. La méthode onStop()
est appelée une fois que l'activité n'est plus visible. Ces rappels semblent être de bons choix pour démarrer et arrêter le minuteur.
- Dans la classe
MainActivity
, démarrez le minuteur du rappelonStart()
:
override fun onStart() {
super.onStart()
dessertTimer.startTimer()
Timber.i("onStart called")
}
- Arrête le minuteur dans
onStop()
:
override fun onStop() {
super.onStop()
dessertTimer.stopTimer()
Timber.i("onStop Called")
}
- Compilez et exécutez l'application. Dans Android Studio, cliquez sur le volet Logcat (Logcat). Dans le champ de recherche de Logcat, saisissez
dessertclicker
, qui filtrera en fonction des classesMainActivity
etDessertTimer
. Notez que l'application s'exécute immédiatement après le démarrage de l'application. - Cliquez sur le bouton Retour et notez que le minuteur s'arrête à nouveau. Le minuteur s'arrête, car l'activité et le minuteur qu'il contrôle ont été détruits.
- Utilisez l'écran des événements récents pour revenir à l'application. Dans Logcat, notez que le minuteur redémarre à partir de 0.
- Cliquez sur le bouton Partager. Notez dans Logcat que le minuteur est toujours en cours d'exécution.
- Cliquez sur le bouton Accueil. Notez dans Logcat que le minuteur s'arrête.
- Utilisez l'écran des événements récents pour revenir à l'application. Dans Logcat, notez que le minuteur redémarre là où il s'était arrêté.
- Dans
MainActivity
, dans la méthodeonStop()
, commentez l'appel destopTimer()
. Le commentairestopTimer()
illustre le cas où vous démarrez une opération dansonStart()
, mais oubliez de l'arrêter à nouveau dansonStop()
. - Compilez et exécutez l'application, puis cliquez sur le bouton d'accueil après le démarrage du minuteur. Même si l'application est en arrière-plan, le minuteur s'exécute et utilise continuellement les ressources du système. Le minuteur continue de s'exécuter, car il s'agit d'une fuite de mémoire pour votre application. Ce n'est probablement pas le comportement que vous souhaitez appliquer.
Lorsque vous configurez ou démarrez un rappel, vous risquez d'arrêter ou de supprimer le rappel associé. Vous éviterez ainsi toute exécution inutile.
- Annulez la mise en commentaire de la ligne dans
onStop()
où vous arrêtez le minuteur. - Couper et coller l'appel
startTimer()
deonStart()
versonCreate()
Cette modification illustre le cas où vous initialisez et démarrez une ressource dansonCreate()
, plutôt que d'utiliseronCreate()
pour l'initialiser etonStart()
pour la démarrer. - Compilez et exécutez l'application. Notez que le minuteur se lance comme prévu.
- Cliquez sur "Home" (Accueil) pour arrêter l'application. Le minuteur s'arrête comme prévu.
- Utilisez l'écran des événements récents pour revenir à l'application. Notez que le minuteur ne redémarre pas dans ce cas, car
onCreate()
n'est appelé que lorsque l'application démarre. Il n'est pas appelé lorsqu'une application revient au premier plan.
Points importants à retenir:
- Lorsque vous configurez une ressource dans un rappel de cycle de vie, vous devez également la supprimer.
- Configurez et supprimez les méthodes correspondantes.
- Si vous avez configuré un élément dans
onStart()
, arrêtez-le ou supprimez-le à nouveau dansonStop()
.
Dans l'application DessertClicker, vous pouvez facilement constater que si vous avez lancé le minuteur dans onStart()
, vous devez l'arrêter dans onStop()
. Il n'y a qu'un seul minuteur, c'est pourquoi il est difficile de le retenir.
Dans une application Android plus complexe, vous pouvez configurer de nombreux éléments dans onStart()
ou onCreate()
, puis tout supprimer dans onStop()
ou onDestroy()
. Par exemple, vous pouvez avoir besoin de configurer ou de supprimer, d'arrêter et d'arrêter des animations, de la musique, des capteurs ou des minuteurs. Si vous en oubliez une, vous risquez de rencontrer des bugs et de vous demander des inquiétudes.
La bibliothèque de cycle de vie, qui fait partie d'Android Jetpack, simplifie cette tâche. La bibliothèque est particulièrement utile lorsque vous devez suivre de nombreuses pièces mobiles, dont certaines ont des états différents. La bibliothèque modifie le fonctionnement des cycles de vie: généralement l'activité ou le fragment indique à un composant (par exemple, DessertTimer
) comment procéder lorsqu'un rappel de cycle de vie se produit. Toutefois, lorsque vous utilisez la bibliothèque de cycle de vie, le composant lui-même surveille les changements de cycle de vie, puis effectue les actions nécessaires lorsque ces changements se produisent.
La bibliothèque de cycle de vie comprend trois parties principales:
- Propriétaires du cycle de vie : les composants qui ont (et donc, possèdent) des cycles de vie.
Activity
etFragment
sont propriétaires du cycle de vie. Les propriétaires de cycle de vie implémentent l'interfaceLifecycleOwner
. - La classe
Lifecycle
, qui contient l'état réel d'un propriétaire du cycle de vie et déclenche des événements lorsque des changements de cycle de vie se produisent. - Des observateurs de cycle de vie, qui observent l'état du cycle de vie et effectuent des tâches lorsque celui-ci change Les observateurs du cycle de vie implémentent l'interface
LifecycleObserver
.
Dans cette tâche, vous allez convertir l'application DessertClicker afin d'utiliser la bibliothèque de cycle de vie Android. Vous découvrirez également comment la bibliothèque facilite l'utilisation des cycles de vie d'activité et de fragment Android.
Étape 1: Transformez DessertMinuteur en Cycle de vie
Un élément clé de la bibliothèque de cycle de vie est le concept d'observation du cycle de vie. L'observation permet aux classes (comme DessertTimer
) de connaître l'activité ou le cycle de vie d'un fragment, puis de s'arrêter et de s'arrêter en réponse aux changements de ces états. Avec un observateur de cycle de vie, vous pouvez arrêter de démarrer et d'arrêter des objets à partir des méthodes d'activité et de fragment.
- Ouvrez la classe
DesertTimer.kt
. - Modifiez la signature de la classe
DessertTimer
comme suit :
class DessertTimer(lifecycle: Lifecycle) : LifecycleObserver {
Cette nouvelle définition de classe a deux conséquences:
- Le constructeur utilise un objet
Lifecycle
, qui correspond au cycle de vie observé par le minuteur. - La définition de classe implémente l'interface
LifecycleObserver
.
- Sous la variable
runnable
, ajoutez un blocinit
à la définition de classe. Dans le blocinit
, utilisez la méthodeaddObserver()
pour connecter l'objet de cycle de vie transmis du propriétaire (l'activité) à cette classe (l'observateur).
init {
lifecycle.addObserver(this)
}
- Annoter
startTimer()
avec@OnLifecycleEvent annotation
et utiliser l'événement de cycle de vieON_START
. Tous les événements de cycle de vie que l'observateur peut observer se trouvent dans la classeLifecycle.Event
.
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun startTimer() {
- Procédez de la même manière pour
stopTimer()
, à l'aide de l'événementON_STOP
:
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stopTimer()
Étape 2: Modifiez MainActivity
Votre classe MainActivity
est déjà propriétaire du cycle de vie via l'héritage, car la super-classe FragmentActivity
implémente LifecycleOwner
. Par conséquent, vous n'avez rien à faire pour que votre activité soit sensible au cycle de vie. Il vous suffit de transmettre l'objet de cycle de vie de l'activité au constructeur DessertTimer
.
- Ouvrez
MainActivity
. Dans la méthodeonCreate()
, modifiez l'initialisation deDessertTimer
pour inclurethis.lifecycle
:
dessertTimer = DessertTimer(this.lifecycle)
La propriété lifecycle
de l'activité contient l'objet Lifecycle
dont elle est propriétaire.
- Supprimez l'appel de
startTimer()
dansonCreate()
et l'appel destopTimer()
dansonStop()
. Vous n'avez plus besoin d'indiquer àDessertTimer
comment procéder dans l'activité. En effet,DessertTimer
observe maintenant le cycle de vie lui-même et est automatiquement alerté lorsqu'il change d'état. Vous n'avez plus qu'à consigner un message dans ces rappels. - Compilez et exécutez l'application, puis ouvrez le fichier Logcat. Notez que le minuteur a démarré, comme prévu.
- Cliquez sur le bouton d'accueil pour passer l'application en arrière-plan. Vous remarquerez que le minuteur s'est arrêté comme prévu.
Qu'advient-il de votre application et de ses données si Android la ferme en arrière-plan ? Il est important de bien comprendre ce cas difficile.
Lorsque votre application passe en arrière-plan, elle n'est pas détruite, elle s'interrompt simplement et attend que l'utilisateur y retourne. Toutefois, l'une des principales préoccupations de l'OS Android est de garantir le bon déroulement de l'activité au premier plan. Par exemple, si votre utilisateur utilise une application GPS pour l'aider à prendre un bus, il est important d'afficher cette application rapidement et de continuer à afficher l'itinéraire. Il est moins important de garder l'application DessertClicker, que l'utilisateur n'a peut-être pas regardée depuis plusieurs jours, en arrière-plan.
Android régule les applications en arrière-plan de sorte qu'elles puissent fonctionner sans problème. Par exemple, Android limite la durée de traitement des applications exécutées en arrière-plan.
Parfois, Android arrête même un processus d'application complet, y compris toute activité associée à l'application. Android effectue ce type d'arrêt lorsque le système est stressé et risque d'être retardé. Par conséquent, aucun rappel ou code supplémentaire n'est exécuté à ce stade. Le processus s'arrête tout simplement en arrière-plan. mais l'utilisateur ne semble pas avoir fermé l'application. Lorsque l'utilisateur revient à une application arrêtée par l'OS Android, Android la redémarre.
Dans cette tâche, vous allez simuler un arrêt d'un processus Android et examiner ce qu'il advient de votre application au redémarrage.
Étape 1: Utilisez adb pour simuler l'arrêt d'un processus
Android Debug Bridge (adb
) est un outil de ligne de commande qui vous permet d'envoyer des instructions aux émulateurs et aux appareils connectés à votre ordinateur. Lors de cette étape, vous allez utiliser adb
pour fermer le processus de votre application et voir ce qui se passe lorsque Android l'arrête.
- Compilez et exécutez votre application. Cliquez plusieurs fois sur le cupcake.
- Appuyez sur le bouton d'accueil pour mettre votre application en arrière-plan. Votre application est maintenant arrêtée, et elle peut être fermée si Android a besoin des ressources qu'elle utilise.
- Dans Android Studio, cliquez sur l'onglet Terminal pour ouvrir le terminal de ligne de commande.
- Saisissez
adb
et appuyez sur Entrée.
Si vous obtenez de nombreux résultats commençant parAndroid Debug Bridge version X.XX.X
et se terminant partags to be used by logcat (see logcat —h
elp, tout va bien. Si, à la place,adb: command not found
s'affiche, vérifiez que la commandeadb
est disponible dans votre chemin d'exécution. Pour obtenir des instructions, consultez la section "Ajouter adb à votre chemin d'exécution" dans le chapitre Utilitaires. - Copiez et collez ce commentaire dans la ligne de commande et appuyez sur Entrée:
.
adb shell am kill com.example.android.dessertclicker
Cette commande indique à tous les appareils ou émulateurs connectés d'arrêter le processus avec le nom de package dessertclicker
, mais uniquement si l'application est exécutée en arrière-plan. Comme votre application était en arrière-plan, rien ne s'affiche sur l'écran de l'appareil ni de l'émulateur pour vous indiquer que le processus a été arrêté. Dans Android Studio, cliquez sur l'onglet Run (Exécuter) pour afficher le message "& term-ed application" (Application arrêtée). Cliquez sur l'onglet Logcat (Logcat) pour vérifier que le rappel onDestroy()
n'a jamais été exécuté. Votre activité s'est simplement terminée.
- Utilisez l'écran "Récents" pour revenir à l'application. Votre application apparaît récemment, si elle a été mise en arrière-plan ou si elle a été complètement arrêtée. Lorsque vous revenez à l'application depuis l'écran des applications récentes, l'activité redémarre. L'activité suit l'ensemble des rappels de cycle de vie au démarrage, y compris
onCreate()
. - Notez que lorsque vous redémarrez l'application, votre "score" est réinitialisé (nombre de desserts vendus et montant total) par défaut (0). Si Android a arrêté votre appli, pourquoi n'a-t-elle pas enregistré son état ?
Lorsque l'OS redémarre votre appli, Android essaie au mieux de réinitialiser l'appli. Android affiche l'état de certaines de vos vues pour les enregistrer dans un groupe lorsque vous quittez l'activité. Voici quelques exemples de données enregistrées automatiquement : le texte dans un TextText (à condition qu'il ait un ID défini dans la mise en page) et la pile "Retour" de votre activité.
Toutefois, il peut arriver qu'Android ne connaisse pas toutes vos données. Par exemple, si vous avez une variable personnalisée telle querevenue
dans l'application DessertClicker, l'OS Android n'a pas connaissance de ces données ni de leur importance pour votre activité. Vous devez ajouter vous-même ces données au lot.
Étape 2: Utilisez onSaveInstanceState() pour enregistrer les données du bundle
La méthode onSaveInstanceState()
est le rappel que vous utilisez pour enregistrer les données dont vous pourriez avoir besoin si l'OS Android détruit votre application. Dans le schéma du rappel de cycle de vie, onSaveInstanceState()
est appelé après l'arrêt de l'activité. Il est appelé à chaque fois que votre application passe en arrière-plan.
Considérez l'appel onSaveInstanceState()
comme une mesure de sécurité. Il vous permet d'enregistrer une petite quantité d'informations dans un groupe lorsque votre activité quitte le premier plan. Le système enregistre maintenant ces données, car il se peut que l'OS subit une pression sur les ressources avant d'avoir arrêté l'application. Chaque fois que vous enregistrez les données, celles-ci peuvent être restaurées, si nécessaire.
- Dans
MainActivity
, ignorez le rappelonSaveInstanceState()
et ajoutez une instruction de journalTimber
.
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
Timber.i("onSaveInstanceState Called")
}
- Compilez et exécutez l'application, puis cliquez sur le bouton Accueil pour la mettre en arrière-plan. Notez que le rappel
onSaveInstanceState()
se produit juste aprèsonPause()
etonStop()
: - En haut du fichier, juste avant la définition de la classe, ajoutez les constantes suivantes:
const val KEY_REVENUE = "revenue_key"
const val KEY_DESSERT_SOLD = "dessert_sold_key"
const val KEY_TIMER_SECONDS = "timer_seconds_key"
Vous utiliserez ces clés pour enregistrer et récupérer les données du groupe d'états de l'instance.
- Faites défiler la page jusqu'à
onSaveInstanceState()
et observez le paramètreoutState
, de typeBundle
.
Un groupe est une collection de paires clé-valeur, où les clés sont toujours des chaînes. Vous pouvez indiquer des valeurs primitives telles queint
etboolean
dans le groupe.
Comme le système conserve ce groupe en mémoire RAM, il est recommandé de réduire la taille des données qu'il contient. La taille de ce lot est également limitée, mais sa taille varie d'un appareil à l'autre. Généralement, vous devez stocker beaucoup moins de 100 000 fichiers, sinon vous risquez de faire planter votre application avec l'erreurTransactionTooLargeException
. - Dans
onSaveInstanceState()
, insérez la valeurrevenue
(un entier) dans le groupe avec la méthodeputInt()
:
outState.putInt(KEY_REVENUE, revenue)
La méthode putInt()
(et les méthodes similaires de la classe Bundle
comme putFloat()
et putString()
) utilisent deux arguments: une chaîne pour la clé (la constante KEY_REVENUE
) et la valeur réelle à enregistrer.
- Effectuez la même procédure avec le nombre de desserts vendus et l'état du minuteur:
outState.putInt(KEY_DESSERT_SOLD, dessertsSold)
outState.putInt(KEY_TIMER_SECONDS, dessertTimer.secondsCount)
Étape 3: Utilisez onCreate() pour restaurer les données du bundle
- Faites défiler la page jusqu'à
onCreate()
et examinez la signature de la méthode:
override fun onCreate(savedInstanceState: Bundle) {
Notez que onCreate()
obtient une Bundle
à chaque appel. Lorsque votre activité est redémarrée en raison d'un arrêt d'un processus, le groupe que vous avez enregistré est transmis à onCreate()
. Si votre activité était lancée récemment, ce groupe dans onCreate()
est null
. Ainsi, si l'activité n'est pas null
, vous savez que vous recréez votre activité.
- Ajoutez ce code à
onCreate()
, après la configuration deDessertTimer
:
if (savedInstanceState != null) {
revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
}
Le test pour null
détermine s'il existe des données dans le bundle ou si le bundle est null
, ce qui vous indique si l'appli a été redémarrée ou a été recréée après un arrêt. Ce test est une pratique courante pour restaurer des données à partir du bundle.
Notez que la clé que vous avez utilisée ici (KEY_REVENUE
) est la même que celle que vous avez utilisée pour putInt()
. Pour vous assurer d'utiliser la même clé à chaque fois, nous vous recommandons de définir ces clés comme constantes. Vous utilisez getInt()
pour récupérer les données du groupe, tout comme vous avez utilisé putInt()
pour saisir les données dans le groupe. La méthode getInt()
comporte deux arguments:
- Chaîne faisant office de clé, par exemple
"key_revenue"
pour la valeur du chiffre d'affaires. - Valeur par défaut si aucune valeur n'existe pour cette clé dans le groupe.
Le nombre entier issu du groupe est ensuite attribué à la variable revenue
, et cette valeur est utilisée dans l'interface utilisateur.
- Ajoutez les méthodes
getInt()
pour restaurer le nombre de desserts vendus et la valeur du minuteur:
if (savedInstanceState != null) {
revenue = savedInstanceState.getInt(KEY_REVENUE, 0)dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
dessertTimer.secondsCount =
savedInstanceState.getInt(KEY_TIMER_SECONDS, 0)
}
- Compilez et exécutez l'application. Appuyez sur le cupcake au moins cinq fois jusqu'à ce qu'il passe à un donut. Cliquez sur "Home" (Accueil) pour mettre l'application en arrière-plan.
- Dans l'onglet Terminal d'Android Studio, exécutez
adb
pour arrêter le processus de l'application.
adb shell am kill com.example.android.dessertclicker
- Utilisez l'écran des récents contenus pour revenir à l'application. Sachez que cette fois, l'application affiche les valeurs de revenus et de desserts vendues par le lot. Mais vous remarquerez aussi que le dessert est de retour dans un cupcake. Il vous reste une dernière tâche à accomplir pour vous assurer que l'application revient après un arrêt exactement comme elle l'avait été.
- Dans
MainActivity
, examinez la méthodeshowCurrentDessert()
. Notez que cette méthode détermine l'image de dessert à afficher dans l'activité en fonction du nombre actuel de desserts vendus et de la liste de desserts de la variableallDesserts
.
for (dessert in allDesserts) {
if (dessertsSold >= dessert.startProductionAmount) {
newDessert = dessert
}
else break
}
Cette méthode repose sur le nombre de desserts vendus afin de choisir l'image appropriée. Vous n'avez donc rien à faire pour stocker une référence à l'image dans le groupe onSaveInstanceState()
. Dans ce lot, vous stockez déjà le nombre de desserts vendus.
- Dans
onCreate()
, dans le bloc qui rétablit l'état du bundle, appelezshowCurrentDessert()
:
if (savedInstanceState != null) {
revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
dessertTimer.secondsCount =
savedInstanceState.getInt(KEY_TIMER_SECONDS, 0)
showCurrentDessert()
}
- Compilez et exécutez l'application, puis placez-la en arrière-plan. Utilisez
adb
pour arrêter le processus. Utilisez l'écran des événements récents pour revenir à l'application. Sachez que les valeurs concernant les desserts indiqués, le total des revenus et l'image du dessert sont correctement restaurées.
Un dernier cas particulier est nécessaire pour gérer l'activité et le cycle de vie des fragments. Il est important de bien comprendre l'impact des modifications de configuration sur le cycle de vie de vos activités et fragments.
Une modification de la configuration se produit lorsque l'état de l'appareil change de manière tellement radicale que le moyen le plus simple pour résoudre le changement consiste à arrêter complètement et à recréer l'activité. Par exemple, s'il modifie la langue de l'appareil, la mise en page devra peut-être être modifiée pour s'adapter aux différentes directions d'affichage du texte. Si l'utilisateur branche l'appareil sur une station d'accueil ou ajoute un clavier physique, la mise en page de l'application devra peut-être profiter d'une taille ou d'une mise en page différentes. En outre, si l'appareil passe de l'orientation portrait à l'arrière-plan ou inversement, la mise en page devra peut-être être modifiée en fonction de la nouvelle orientation.
Étape 1: Explorez la rotation des appareils et les rappels de cycle de vie
- Compilez et exécutez votre application, puis ouvrez Logcat.
- Faites pivoter l'appareil ou l'émulateur en mode Paysage. Vous pouvez faire pivoter l'émulateur à gauche ou à droite à l'aide des boutons de rotation, ou à l'aide des touches
Control
et fléchées (Command
et des flèches) sur un Mac. - Examinez la sortie dans Logcat. Filtrez le résultat sur
MainActivity
.
Notez que lorsque l'appareil ou l'émulateur fait pivoter l'écran, le système appelle tous les rappels de cycle de vie pour arrêter l'activité. Ensuite, lorsque l'activité est recréée, le système appelle tous les rappels de cycle de vie pour démarrer l'activité. - Dans
MainActivity
, mettez en commentaire toute la méthodeonSaveInstanceState()
. - Compilez et exécutez à nouveau votre application. Cliquez plusieurs fois sur le cupcake, puis faites pivoter l'appareil ou l'émulateur. Cette fois, lorsque vous faites pivoter l'appareil et que l'activité est arrêtée, puis recréée, l'activité démarre avec des valeurs par défaut.
Lorsqu'une modification de configuration se produit, Android utilise le même groupe d'états d'instance que vous avez appris dans la tâche précédente pour enregistrer et restaurer l'état de l'application. Comme pour un arrêt de processus, utilisezonSaveInstanceState()
pour placer les données de votre application dans le bundle. Ensuite, restaurez les données dansonCreate()
pour éviter de perdre des données d'état d'activité si l'appareil est tourné. - Dans
MainActivity
, annulez la mise en commentaire de la méthodeonSaveInstanceState()
, exécutez l'application, cliquez sur le cupcake et faites-la pivoter l'application ou l'appareil. Cette fois, les données du dessert sont conservées pendant la rotation de l'activité.
Projet Android Studio: DessertClickerFinal
Conseils sur le cycle de vie
- Si vous avez configuré ou démarré un rappel dans le cycle de vie, arrêtez ou supprimez cette action dans le rappel correspondant. En arrêtant ce qui se passe, vous vous assurez qu'il ne sera plus utilisé quand il ne sera plus nécessaire. Par exemple, si vous définissez un minuteur dans
onStart()
, vous devez le suspendre ou l'arrêter dansonStop()
. - Utilisez
onCreate()
uniquement pour initialiser les parties de votre application qui s'exécutent une fois, au démarrage de l'application. UtilisezonStart()
pour démarrer les parties de votre application qui s'exécutent au démarrage et à chaque fois qu'elle retourne au premier plan.
Bibliothèque de cycle de vie
- Utilisez la bibliothèque de cycle de vie Android pour remplacer le contrôle du cycle de vie de l'activité ou du fragment par le composant lui-même sensible au cycle de vie.
- Les propriétaires de cycle de vie sont des composants qui ont des cycles de vie (et donc les propres) tels que
Activity
etFragment
. Les propriétaires de cycle de vie implémentent l'interfaceLifecycleOwner
. - Les observateurs du cycle de vie consultent l'état actuel du cycle de vie et effectuent des tâches lorsque celui-ci change. Les observateurs du cycle de vie implémentent l'interface
LifecycleObserver
. - Les objets
Lifecycle
contiennent les états réels du cycle de vie et déclenchent des événements lorsque le cycle de vie change.
Pour créer une classe prenant en compte le cycle de vie, procédez comme suit:
- Implémentez l'interface
LifecycleObserver
dans les classes qui doivent tenir compte du cycle de vie. - Initialisez une classe d'observateur de cycle de vie avec l'objet de cycle de vie de l'activité ou du fragment.
- Dans la classe d'observateur du cycle de vie, annotez les méthodes compatibles avec ce cycle avec le changement de l'état du cycle qui les intéresse.
Par exemple, l'annotation@OnLifecycleEvent(Lifecycle.Event.ON_START)
indique que la méthode surveille l'événement de cycle de vieonStart
.
Traitement des coupures et enregistrement de l'état d'activité
- Android régule les applications exécutées en arrière-plan de sorte qu'elles puissent fonctionner sans problème. Ces réglementations imposent des restrictions en ce qui concerne le traitement des applications en arrière-plan, voire l'arrêt de l'ensemble du processus d'applications.
- L'utilisateur ne peut pas savoir si le système a arrêté une application en arrière-plan. L'application s'affiche toujours sur l'écran des applications récentes et doit redémarrer dans l'état où l'utilisateur l'a laissée.
- Android Debug Bridge (
adb
) est un outil de ligne de commande qui vous permet d'envoyer des instructions aux émulateurs et aux appareils connectés à votre ordinateur. Vous pouvez utiliseradb
pour simuler un arrêt d'un processus dans votre application. - Lorsque Android arrête le processus de votre application, la méthode de cycle de vie
onDestroy()
n'est pas appelée. L'appli s'arrête.
Conserver l'activité et l'état du fragment
- Lorsque votre application passe en arrière-plan, juste après l'appel de
onStop()
, les données de l'application sont enregistrées dans un groupe. Certaines données d'application telles que le contenu d'uneEditText
sont automatiquement enregistrées. - Le groupe est une instance de
Bundle
, qui est une collection de clés et de valeurs. Les clés sont toujours des chaînes. - Utilisez le rappel
onSaveInstanceState()
pour enregistrer d'autres données dans le groupe que vous souhaitez conserver, même si l'application a été arrêtée automatiquement. Pour saisir des données dans le groupe, utilisez les méthodes du groupe qui commencent parput
, par exempleputInt()
. - Vous pouvez récupérer les données du groupe dans la méthode
onRestoreInstanceState()
ou, plus généralement, dansonCreate()
. La méthodeonCreate()
comporte un paramètresavedInstanceState
qui contient le groupe. - Si la variable
savedInstanceState
contientnull
, l'activité a commencé sans groupe d'états et il n'existe aucune donnée d'état à récupérer. - Pour récupérer les données du groupe à l'aide d'une clé, utilisez les méthodes
Bundle
qui commencent parget
, par exemplegetInt()
.
Modifications de configuration
- Une modification de la configuration se produit lorsque l'état de l'appareil change de manière tellement radicale que le moyen le plus simple pour résoudre le changement consiste à arrêter et à recréer l'activité.
- L'exemple de modification de configuration le plus courant est lorsque l'utilisateur fait pivoter l'appareil du mode portrait au mode paysage, ou du mode paysage au mode portrait. Une modification de la configuration peut également se produire lorsque la langue de l'appareil change ou que le clavier matériel est branché.
- Lorsqu'une modification de configuration se produit, Android appelle tous les rappels d'arrêt liés au 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.
- Lorsque Android arrête une application en raison d'une modification de la configuration, il redémarre l'activité avec le bundle d'état disponible pour
onCreate()
. - Comme pour l'arrêt du processus, enregistrez l'état de votre application dans le groupe dans
onSaveInstanceState()
.
Cours Udacity:
Documentation pour les développeurs Android:
- Activités (guide de l'API)
Activity
(référence de l'API)- Comprendre le cycle de vie de l'activité
- Gérer les cycles de vie avec les composants du cycle de vie
LifecycleOwner
Lifecycle
LifecycleObserver
onSaveInstanceState()
- Gérer les modifications de configuration
- Enregistrer des états d'interface utilisateur
Autre :
- Timber (GitHub)
Cette section répertorie les devoirs possibles pour les élèves qui effectuent cet atelier de programmation dans le cadre d'un cours animé par un enseignant. C'est à l'enseignant de procéder comme suit:
- Si nécessaire, rendez-les.
- Communiquez aux élèves comment rendre leurs devoirs.
- Notez les devoirs.
Les enseignants peuvent utiliser ces suggestions autant qu'ils le souhaitent, et ils n'ont pas besoin d'attribuer les devoirs de leur choix.
Si vous suivez vous-même cet atelier de programmation, n'hésitez pas à utiliser ces devoirs pour tester vos connaissances.
Modifier une application
Ouvrez l'application DiceRoller de la leçon 1. (Vous pouvez télécharger l'application si vous ne l'avez pas installée.) Compilez et exécutez l'application. Notez que si vous faites pivoter l'appareil, la valeur actuelle du dé est perdue. Intégrez onSaveInstanceState()
pour conserver cette valeur dans le groupe et restaurer cette valeur dans onCreate()
.
Répondez à ces questions.
Question 1
Votre application contient une simulation physique qui nécessite un calcul complexe. L'utilisateur reçoit alors un appel téléphonique. Parmi ces affirmations, laquelle est exacte ?
- Pendant l'appel téléphonique, vous devez continuer à calculer la position des objets dans la simulation physique.
- Lors de l'appel téléphonique, vous devez cesser de calculer les positions des objets dans la simulation physique.
Question 2
Quelle méthode de cycle de vie devez-vous remplacer pour suspendre la simulation lorsque l'application ne s'affiche pas à l'écran ?
onDestroy()
onStop()
onPause()
onSaveInstanceState()
Question 3
Quelle interface la classe doit-elle mettre en œuvre pour qu'elle puisse prendre en compte le cycle de vie dans la bibliothèque Android ?
Lifecycle
LifecycleOwner
Lifecycle.Event
LifecycleObserver
Question 4
Dans quels cas la méthode onCreate()
dans votre activité reçoit-elle un Bundle
avec des données (c'est-à-dire que Bundle
n'est pas null
) ? Plusieurs réponses peuvent s'appliquer.
- L'activité est redémarrée après la rotation de l'appareil.
- L'activité a démarré de zéro.
- L'activité est réactivée après un retour en arrière-plan.
- L'appareil est redémarré.
Démarrez la leçon suivante:
Pour obtenir des liens vers d'autres ateliers de programmation dans ce cours, consultez la page de destination des ateliers de programmation Android Kotlin Fundamentals.