Lancez l'application, saisissez votre prénom et appuyez sur le bouton de démarrage de jeu. Observez la question posée. Tournez votre téléphone pour changer l'orientation (si vous êtes en mode portrait, passez en mode paysage, et vice-versa). Répétez l'opération plusieurs fois. Que constatez-vous ? La question posée est presque à chaque fois différente ! Pourquoi ? C'est ce que nous allons découvrir dans ce chapitre.
Le changement d'orientation
Nous sommes tous libres de changer d'orientation. Regardez, avant j'étais agent secret, maintenant je suis votre professeur Android préféré. Ah non, je m'égare, ce n'est pas de ce changement d'orientation que je voulais parler !
Vous l'aviez compris, je voulais plutôt parler du changement d'orientation de votre équipement. Je vais être très vilain et vous ôter tout suspens : lorsque le système Android effectue une rotation de l'écran, il détruit votre activité et la crée de nouveau. Oui je suis d'accord, c'est inadmissible !
Pour vous en convaincre, regardez les traces lorsque vous tournez l'équipement (si vous êtes comme Dexter et les avez toutes effacées, c'est très bien, mais il va falloir les remettre pour voir la même chose) :
2021-06-03 17:55:42.536 9618-9618/fr.delcey.topquiz D/Nino: onPause() called
2021-06-03 17:55:42.538 9618-9618/fr.delcey.topquiz D/Nino: onStop() called
2021-06-03 17:55:42.539 9618-9618/fr.delcey.topquiz D/Nino: onDestroy() called
2021-06-03 17:55:42.606 9618-9618/fr.delcey.topquiz D/Nino: onCreate() called
2021-06-03 17:55:42.678 9618-9618/fr.delcey.topquiz D/Nino: onStart() called
2021-06-03 17:55:42.679 9618-9618/fr.delcey.topquiz D/Nino: onResume() called
C'est sans appel : l'activité est bien arrêtée puis démarrée de nouveau. Suivant l'activité, la conséquence est plus ou moins importante :
dans la MainActivity, cela est transparent pour l'utilisateur, car son prénom et son score sont chargés depuis les préférences à chaque démarrage de l'activité, dans la méthode onCreate() ;
dans la GameActivity, c'est plus problématique. À chaque démarrage, une nouvelle liste de questions est générée, le score est perdu et l'avancée aussi.
Sauvegarde et restauration des données
Heureusement, Android ne nous laisse pas seuls sur le bord de la route avec notre problème. Avant d'arrêter une activité, Android appelle la méthode suivante sur l'instance en cours :
public void onSaveInstanceState(Bundle savedInstanceState);
Le paramètre savedInstanceState (ou parfois nommé outState) vous rappelle quelque chose ? Exactement, c'est la même information qui est passée en paramètre de la méthode onCreate(). En d'autres termes, dans la méthode onSaveInstanceState(), nous allons ajouter au Bundle toutes les informations pertinentes nous permettant de revenir dans l'état dans lequel nous nous trouvions avant que l'activité soit redémarrée. Les deux paramètres que nous allons sauvegarder sont le score de l'utilisateur et l'indice de la question à laquelle il est rendu.
Par mesure de simplicité, nous n'allons pas sauvegarder les questions déjà posées pour éviter d'afficher les mêmes, car c'est un sujet assez complexe. De ce fait, dans le cadre de ce cours, il faut accepter de retomber éventuellement sur les mêmes questions.
Le principe de sauvegarde dans le Bundle est identique aux SharedPreferences ou aux Intent : vous devez préciser une clé, et utiliser la méthode correspondant au type de la donnée à sauvegarder. Sachant que nous souhaitons sauvegarder deux entiers, nous allons utiliser la méthode putInt().
Afin de récupérer les données plus facilement, créez les deux clés sous forme de constantes dans la classe GameActivity :
public static final String BUNDLE_STATE_SCORE = "BUNDLE_STATE_SCORE";
public static final String BUNDLE_STATE_QUESTION = "BUNDLE_STATE_QUESTION";
Ensuite, sauvegardez la valeur du score et de l'index de questions, et surtout n'oubliez pas d'appeler l'implémentation de la classe mère :
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(BUNDLE_STATE_SCORE, mScore);
outState.putInt(BUNDLE_STATE_QUESTION, mRemainingQuestionCount);
}
Maintenant, il vous suffit de récupérer ces valeurs dans la méthode onCreate(), en vous assurant que le paramètre Bundle est bien valorisé (il peut valoir null, notamment lorsque l'activité est démarrée pour la première fois) :
if (savedInstanceState != null) {
mScore = savedInstanceState.getInt(BUNDLE_STATE_SCORE);
mRemainingQuestionCount = savedInstanceState.getInt(BUNDLE_STATE_QUESTION);
} else {
mScore = 0;
mRemainingQuestionCount = 4;
}
Il est également possible d'utiliser le pendant de la méthode onSaveInstanceState(), qui est onRestoreInstanceState(). Je vous laisse découvrir comment l'implémenter sur cette page.
Récapitulons en vidéo
Retrouvez ces différentes étapes dans la vidéo ci-dessous :
Vous avez découvert les fondamentaux de la programmation Android, à savoir le fonctionnement d'Android Studio, la construction d'une interface graphique (avec une Activity), le branchement des widgets (vues) dans le code, le MVC (la logique business de l'application), les SharedPreferences (pour persister des informations) et le cycle de vie d'une activité. Wahou ! Rien qu'avec ces connaissances, vous allez déjà pouvoir développer de chouettes petites applications.
N'hésitez pas à fouiner dans le guide des API Android ainsi que dans les différents chapitres de la documentation.
En résumé
Lorsque le système Android effectue une rotation de l'écran, il détruit votre activité et la crée de nouveau.
dans la méthode onSaveInstanceState(), ajoutez au Bundle toutes les informations pertinentes nous permettant de revenir dans l'état précédent.
Le principe de sauvegarde dans le Bundle est identique aux SharedPreferences ou aux Intent : vous devez préciser une clé, et utiliser la méthode correspondant au type de la donnée à sauvegarder.