Les différents états d'une application
Lors de son exécution, une application passe par différents états selon les actions effectuées
soit par l'utilisateur (lancement d'une autre aplication, rotation de l'écran), soit par le système (affichage d'une notification type
sms, réception d'un appel, gestion de la mémoire). Le système Android utilise un mécanisme de
pile pour gêrer les applications. Lorsqu'une application s'exécute, elle est placée au sommet de la pile
et l'utilisateur peut interagir avec cette dernière. L'application qui avait précédemment le focus,
le perd et continue son exécution en arrière plan, elle reste donc active en mémoire. Si jamais la pile
est pleine au moment du lancement d'une nouvelle application, l'application située en bas de pile est détruite
par le système et son emplacement mémoire est libéré.
Dans le cycle de vie d'une application, on peut distinguer essentiellement trois états:
- L'application est active, l'utilisateur interagit avec cette dernière.
- L'application a perdu le focus mais est toujours visible à l'écran, elle est en pause.
C'est le cas par exemple lorsq'un message d'alerte vient s'afficher par dessus votre application. Dans cet état,
le système peut décider si cela est nécessaire de détruire l'application.
- L'application n'est plus visible, mais elle est toujours résidente en mémoire, elle est stoppée.
Dans cette situation, le système peut à nouveau décider de détruire l'application pour
libérer de la mémoire.
Le diagramme ci-dessous disponible sur le site officiel
developer.andoid.com illustre le cyle de vie
d'une application en spécifiant les différentes méthodes qui sont exécutées selon le contexte.
Lors du développement d'une application, il est important de prendre en compte que:
- La vie complète d'une activité se déroule entre le premier appel à la méthode
onCreate
et l'appel de la méthode onDestroy
.
- L'intervalle durant lequel l'application est visible est délimité par l'appel des méthodes
onStart
et onStop
. Attention, l'application est visible, ce qui ne signifie pas forcément
que l'utilisateur peut interagir avec cette dernière.
- L'intervalle durant lequel l'utilisateur peut interagir avec l'application correspond à l'appel des méthodes
onResume
et onPause
.
onCreate(Bundle state)
Cette méthode est exécutée lors du premier lancement de l'application. Elle prend en paramètre un objet de type
Bundle qui correspond à une sorte de dictionnaire permettant d'associer à une clé
(une chaîne de caractères), un objet (booléen, entier, réel, chaîne de caractères,
tableau, classe sérialisable,...). Ainsi avant qu'une application soit détruite, il est possible de sauvegarder
certains objets et de les récupérer via ce Bundle lorsque l'application est relancée (cf. paragraphe
Sauvegarde et restauration des données).
onStart()
Cette méthode est exécutée à chaque fois que l'utilisateur lance une application non visible,
qu'elle fasse partie ou non de la pile des applications en cours. L'application devient alors visible.
onRestart()
Exécutée à chaque fois que l'utilisateur relance une application non visible qui faisait partie
de la pile des applications en cours (i.e. résidente en mémoire). Dans ce cas, cette méthode
est exécutée avant la méthode onStart
.
onResume()
Exécutée (après onStart
) lorsque :
- L'application est lancée pour la première fois.
- L'application (invisible) est relancée et fait partie de la pile des applications en cours
Exécutée (après
onPause
) lorsque l'application est visible en arrière plan
et qu'elle reprend le focus.
onPause()
Exécutée lorsque l'application perd le focus et ne se trouve donc plus au premier plan, soit suite
à une action du système (réception d'un message par exemple), soit suite à une action
de l'utilisateur (passage à une autre application). C'est dans cette méthode qu'il faudra penser
à "désactiver" toutes les ressources utiles uniquement lorsque l'application est visible et qui
sont consommatrices de CPU, ou de batterie.
onStop()
Exécutée lorsque l'application n'est plus visible, soit parce qu'elle va être détruite,
soit parce qu'elle va passer en arrière plan dans la pile des applications en cours.
onDestroy()
Exécutée lorsque l'application va être détruite. On pensera à ce stade à
libérer toutes les ressources allouées par l'application (les connexions réseaux ouvertes par exemple).
Sauvegarde et restauration des données
D'après le diagramme du cycle de vie d'une application, il apparaît qu'après l'appel de la
méthode onPause()
ou onStop()
, le système peut décider de détruire
l'application. La méthode onPause()
étant la première à être exécutée,
c'est donc dans cette dernière qu'il faut placer des instructions de sauvegarde de certaines données que l'on
souhaiterait pouvoir retrouver si l'application est détruite par le système et relancée par l'utilisateur.
Nous allons traiter ceci à travers un exemple.
Exercice : Définissez un nouveau Projet nommé
CycleActivity et créez
un layout permettant d'obtenir le rendu visuel suivant (il faudra prévoir une zone d'affichage de texte
sous le bouton
Show).
Exercice : Complétez le fichier
CycleActivity.java de façon à ce que:
- Lorsque l'on clique sur le bouton Save, le texte saisi par l'utilisateur dans la zone
pourvue à cet effet, soit sauvegardé dans la variable globale texte.
- Lorsque l'on clique sur le bouton Show, le contenu de la variable texte soit affiché
dans la zone de texte déclarée après le bouton Show.
Exécutez votre application comme suit :
- Entrez un texte, cliquez sur Save, puis sur Show.
- Entrez un nouveau texte, cliquez sur Save. Pivotez votre téléphone
pour le mettre en mode paysage, puis cliquez sur Show. Que constatez-vous ?
Le contenu de la variable globale
texte a été perdu. En utilisant les messages de log pour faire afficher les
différentes étapes du cycle de vie de votre application, vous pouvez observer que lors du pivotement de l'écran,
votre application est détruite par le système (appel à
onDestroy()). En effet lors de la rotation de l'écran,
il se peut que l'application doive appliquer un nouveau layout plus adapté à l'orientation de ce dernier. Or c'est l'instruction
setContentView(R.layout....) de la méthode
onCreate() qui se charge de cette tâche. La méthode
onCreate()
n'étant exécutée qu'au lancement de l'application, il est donc nécessaire de relancer celle-ci.
Exercice : Modifiez votre application de façon à ce que la méthode
show affiche aussi le texte saisi par
l'utilisateur en utilisant directement la méthode
getText() et non pas en utilisant la variable
texte. Exécutez votre
application, saisissez une valeur, cliquez sur
Save, puis sur
Show, faites pivoter votre écran et cliquez à nouveau
sur
Show/ Que constatez-vous~?
Le contenu de la zone de texte a été sauvegardé et il s'affiche après la rotation de l'écran. Pour chaque objet de
type
View, Android sauvegarde automatiquement certaines informations (tel que le texte saisi par l'utilisateur dans une zone d'édition)
dans un objet de type
Bundle. Il s'agit d'une sorte de dictionnaire permettant d'associer un objet (chaine de caractères, tableau
d'entiers, tout objet sérialisable, ...) à une clé (une chaine de caractères). Lorsque la méthode
onCreate()
s'exécute elle recçoit en paramètre cet objet et c'est l'appel du superconstructeur de
onCreate() qui se charge de rétablir
les informations sauvés.
Important Pour que ceci fonctionne, il est indispensable que chaque objet de type
View défini dans le layout possède un
identifiant via l'attribut
android:id.
Si pour les besoins de votre application, vous devez sauvegarder des données autres que celles attachées à des vues, vous
allez devoir redéfinir la méthode
onSaveInstanceState(). Cette dernière est automatiquement appelée par la
méthode
onPause() et prend en paramètre un objet de type
Bundle que l'on peut utiliser pour sauvegarder des informations.
Ainsi pour conserver la valeur de la variable
texte, il suffit d'utiliser la méthode
putString(clé
,valeur
)
de la classe
Bundle pour associer à la clé
clé
, la valeur sauvegardée.
Lorsque la méthode
onCreate s'exécute, il suffit de vérifier si l'objet de type
Bundle reçu en paramètre
n'est pas vide, auquel cas on pourra récupérer la ou les valeurs sauvegardées.
Une autre façon de procéder consiste à redéfinir la méthode
onRestoreInstanceState(Bundle B) qui est
exécutée par la méthode
onStart() uniquement si le paramètre
B n'est pas vide. Il est alors inutile de faire
ce test dans la méthode
onCreate().
ATTENTION ! Dans ce cas, il est important de ne pas oublier de faire appel au super constructeur de la méthode
onRestoreInstanceState qui se charge de sauvegarder automatiquement les informations liées aux objets de type
View.
Remarque importante : cette sauvegarde des données ne fonctionne que dans le cas où c'est le système qui décide
de détruire l'application pour la relancer immédiatement (cas de la rotation de l'écran). Si l'utilisateur quitte
volontairement l'application (exécution de la méthode
onDestroy), ou si le système supprime l'application sans la relancer,
les données placées dans le Bundle sont perdues. Afin de conserver et restaurer des données entre deux exécutions
d'une application, on peut alors par exemple utiliser le ménisme des
Shared Preferences ou une base de données.