Certaines configurations d'appareil peuvent changer pendant l'exécution de l'application. Voici quelques exemples :
- Taille d'affichage de l'application
- Orientation de l'écran
- Taille et épaisseur de la police
- Paramètres régionaux
- Mode sombre ou mode clair
- Disponibilité du clavier
La plupart de ces modifications de configuration se produisent en raison d'une interaction de l'utilisateur. Par exemple, la rotation ou le pliage de l'appareil modifient la quantité d'espace d'écran disponible pour votre application. De même, la modification des paramètres de l'appareil, tels que la taille de la police, la langue ou le thème préféré, modifie leurs valeurs respectives dans l'objet Configuration.
Ces paramètres nécessitent généralement des modifications suffisamment importantes de l'UI de votre application pour que la plate-forme Android dispose d'un mécanisme spécialement conçu pour leur modification.
Ce mécanisme est la recréation de Activity.
Recréation d'activité
Le système recrée une Activity lorsqu'une modification de configuration se produit. Pour ce faire, le système appelle onDestroy() et détruit l'instance Activity existante. Il crée ensuite une instance à l'aide de onCreate(). Cette nouvelle instance Activity est initialisée avec la nouvelle configuration mise à jour. Cela signifie également que le système recrée l'UI avec la nouvelle configuration.
Le comportement de recréation aide votre application à s'adapter aux nouvelles configurations en rechargeant automatiquement votre application avec des ressources alternatives correspondant à la nouvelle configuration de l'appareil.
Exemple de loisirs
Prenons l'exemple d'un TextView qui affiche un titre statique à l'aide de android:text="@string/title", tel que défini dans un fichier XML de mise en page. Lorsque la vue est créée, le texte est défini une seule fois, en fonction de la langue actuelle. Si la langue change, le système recrée l'activité. Par conséquent, le système recrée également la vue et l'initialise à la valeur correcte en fonction de la nouvelle langue.
La recréation efface également tout état conservé sous forme de champs dans Activity ou dans l'un de ses objets Fragment, View ou autres. En effet, la recréation de Activity crée une instance entièrement nouvelle de Activity et de l'UI. De plus, l'ancien Activity n'est plus visible ni valide. Par conséquent, toutes les références restantes à celui-ci ou à ses objets contenus sont obsolètes. Ils peuvent provoquer des bugs, des fuites de mémoire et des plantages.
Attentes des utilisateurs
L'utilisateur d'une application s'attend à ce que l'état soit conservé. Si un utilisateur remplit un formulaire et ouvre une autre application en mode multifenêtre pour consulter des informations, il est désagréable pour lui de revenir à un formulaire effacé ou à un autre endroit de l'application. En tant que développeur, vous devez fournir une expérience utilisateur cohérente lors des modifications de configuration et de la recréation d'activité.
Pour vérifier si l'état est conservé dans votre application, vous pouvez effectuer des actions qui entraînent des modifications de configuration lorsque l'application est au premier plan et lorsqu'elle est en arrière-plan. Ces actions incluent :
- Faire pivoter l'appareil
- Activer le mode multifenêtre
- Redimensionner l'application en mode multifenêtre ou dans une fenêtre de format libre
- Plier un appareil pliable à plusieurs écrans
- Changer le thème du système (par exemple, passer du mode sombre au mode clair)
- Modifier la taille de la police
- Modifier la langue du système ou de l'application
- Connecter ou déconnecter un clavier physique
- Connecter ou déconnecter une station de recharge
Il existe trois approches principales pour préserver l'état pertinent lors de la recréation de Activity. Le choix dépend du type d'état que vous souhaitez conserver :
- La persistance locale pour gérer l'arrêt du processus pour des données complexes ou volumineuses.
Le stockage local persistant inclut les bases de données ou
DataStore. - Des objets conservés tels que les instances
ViewModelpour gérer l'état lié à l'UI en mémoire pendant que l'utilisateur utilise activement l'application. - L'état d'instance enregistré pour gérer un arrêt de processus déclenché par le système et conserver l'état temporaire qui dépend de l'entrée utilisateur ou de la navigation.
Pour en savoir plus sur les API pour chacun de ces cas et sur le moment où il convient d'utiliser chacune d'elles, consultez Enregistrer les états de l'UI.
Restreindre la recréation d'activité
Vous pouvez empêcher la recréation automatique de l'activité pour certaines modifications de configuration.
La recréation de Activity entraîne la recréation de l'intégralité de l'UI et de tous les objets dérivés de Activity. Vous avez peut-être de bonnes raisons d'éviter cela. Par exemple, votre application n'a peut-être pas besoin de mettre à jour les ressources lors d'un changement de configuration spécifique, ou vous pouvez avoir une limite de performances. Dans ce cas, vous pouvez déclarer que votre activité gère elle-même la modification de configuration et empêcher le système de la redémarrer.
Pour désactiver la recréation d'activité pour des modifications de configuration spécifiques, ajoutez le type de configuration à android:configChanges dans l'entrée <activity> de votre fichier AndroidManifest.xml. Les valeurs possibles figurent dans la documentation de l'attribut android:configChanges.
Le code de fichier manifeste suivant désactive la recréation de Activity pour MyActivity lorsque l'orientation de l'écran et la disponibilité du clavier changent :
<activity
android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:label="@string/app_name">
Certaines modifications de configuration entraînent toujours le redémarrage de l'activité. Vous ne pouvez pas les désactiver. Par exemple, vous ne pouvez pas désactiver le changement de couleurs dynamiques introduit dans Android 12L (niveau d'API 32).
Réagir aux modifications de configuration dans le système View
Dans le système View, lorsqu'une modification de configuration se produit pour laquelle vous avez désactivé la recréation Activity, l'activité reçoit un appel à Activity.onConfigurationChanged(). Toutes les vues associées reçoivent également un appel à View.onConfigurationChanged(). Pour les modifications de configuration que vous n'avez pas ajoutées à android:configChanges, le système recrée l'activité comme d'habitude.
La méthode de rappel onConfigurationChanged() reçoit un objet Configuration qui spécifie la nouvelle configuration de l'appareil. Lisez les champs de l'objet Configuration pour déterminer votre nouvelle configuration. Pour apporter les modifications ultérieures, mettez à jour les ressources que vous utilisez dans votre interface. Lorsque le système appelle cette méthode, l'objet Resources de votre activité est mis à jour pour renvoyer des ressources en fonction de la nouvelle configuration. Vous pouvez ainsi réinitialiser des éléments de votre UI sans que le système redémarre votre activité.
Par exemple, l'implémentation onConfigurationChanged() suivante vérifie si un clavier est disponible :
Kotlin
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Checks whether a keyboard is available
if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show()
} else if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_NO) {
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show()
}
}
Java
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks whether a keyboard is available
if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show();
} else if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO){
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show();
}
}
Si vous n'avez pas besoin de mettre à jour votre application en fonction de ces modifications de configuration, vous pouvez choisir de ne pas implémenter onConfigurationChanged(). Dans ce cas, toutes les ressources utilisées avant la modification de la configuration sont toujours utilisées et vous avez seulement évité le redémarrage de votre activité. Par exemple, une application TV peut ne pas vouloir réagir lorsqu'un clavier Bluetooth est connecté ou déconnecté.
Conserver l'état
Lorsque vous utilisez cette technique, vous devez toujours conserver l'état pendant le cycle de vie normal d'une activité. Voici pourquoi :
- Modifications inévitables : les modifications de configuration que vous ne pouvez pas empêcher peuvent redémarrer votre application.
- Arrêt de processus : votre application doit être capable de gérer l'arrêt de processus initié par le système. Si l'utilisateur quitte votre application et qu'elle passe en arrière-plan, il est possible que le système la détruise.
Réagir aux modifications de configuration dans Jetpack Compose
Jetpack Compose permet à votre application de réagir plus facilement aux modifications de configuration.
Toutefois, même si vous désactivez la recréation de Activity pour toutes les modifications de configuration où cela est possible, votre application doit toujours gérer correctement les modifications de configuration.
L'objet Configuration est disponible dans la hiérarchie de l'UI Compose avec la composition locale LocalConfiguration. Chaque fois qu'il change, les fonctions composables qui lisent LocalConfiguration.current sont recomposées. Pour en savoir plus sur le fonctionnement des CompositionLocals, consultez Données à champ d'application local avec CompositionLocal.
Exemple
Dans l'exemple suivant, un composable affiche une date dans un format spécifique.
Le composable réagit aux modifications de configuration des paramètres régionaux du système en appelant ConfigurationCompat.getLocales() avec LocalConfiguration.current.
@Composable
fun DateText(year: Int, dayOfYear: Int) {
val dateTimeFormatter = DateTimeFormatter.ofPattern(
"MMM dd",
ConfigurationCompat.getLocales(LocalConfiguration.current)[0]
)
Text(
dateTimeFormatter.format(LocalDate.ofYearDay(year, dayOfYear))
)
}
Pour éviter la recréation de Activity lorsque les paramètres régionaux changent, le Activity hébergeant le code Compose doit désactiver les modifications de configuration des paramètres régionaux. Pour ce faire, définissez android:configChanges sur locale|layoutDirection.
Modifications de la configuration : concepts clés et bonnes pratiques
Voici les concepts clés à connaître lorsque vous modifiez la configuration :
- Configurations : les configurations d'appareil définissent la manière dont l'UI s'affiche pour l'utilisateur, par exemple la taille d'affichage de l'application, la langue ou le thème du système.
- Modifications de la configuration : les configurations changent en fonction des interactions des utilisateurs. Par exemple, l'utilisateur peut modifier les paramètres de l'appareil ou la façon dont il interagit physiquement avec l'appareil. Il n'existe aucun moyen d'empêcher les modifications de configuration.
- Recréation de
Activity: les modifications de configuration entraînent la recréation deActivitypar défaut. Il s'agit d'un mécanisme intégré permettant de réinitialiser l'état de l'application pour la nouvelle configuration. - Destruction de
Activity: la recréation deActivityentraîne la destruction de l'ancienne instanceActivityet la création d'une nouvelle à sa place. L'ancienne instance est désormais obsolète. Toute référence restante à celui-ci entraîne des fuites de mémoire, des bugs ou des plantages. - L'état de l'ancienne instance
Activityn'est pas présent dans la nouvelle instanceActivity, car il s'agit de deux instances d'objet différentes. Conservez l'état de l'application et de l'utilisateur, comme décrit dans Enregistrer les états de l'interface utilisateur. - Désactivation : la désactivation de la recréation d'activité pour un type de modification de configuration est une optimisation potentielle. Elle exige que votre application se mette à jour correctement en réaction à la nouvelle configuration.
Pour offrir une expérience utilisateur de qualité, suivez les bonnes pratiques suivantes :
- Préparez-vous à des changements de configuration fréquents : ne partez pas du principe que les changements de configuration sont rares ou n'arrivent jamais, quel que soit le niveau d'API, le facteur de forme ou la boîte à outils d'UI. Lorsqu'un utilisateur modifie la configuration, il s'attend à ce que les applications se mettent à jour et continuent de fonctionner correctement avec la nouvelle configuration.
- Conserver l'état : ne pas perdre l'état de l'utilisateur lors de la recréation de
Activity. Conservez l'état comme décrit dans Enregistrer les états de l'UI. - Évitez de désactiver la recréation comme solution rapide : ne désactivez pas la recréation de
Activitycomme raccourci pour éviter la perte d'état. Si vous désactivez la recréation d'activité, vous devez tenir votre promesse de gérer le changement. Vous pouvez toujours perdre l'état en raison de la recréation deActivitysuite à d'autres modifications de configuration, à l'arrêt du processus ou à la fermeture de l'application. Il est impossible de désactiver complètement la recréation deActivity. Conservez l'état comme décrit dans Enregistrer les états de l'UI. - Ne pas éviter les modifications de configuration : ne pas imposer de restrictions sur l'orientation, le format ou la redimensionnabilité pour éviter les modifications de configuration et la recréation de
Activity. Cela nuit aux utilisateurs qui souhaitent utiliser votre application de la manière qui leur convient.
Gérer les modifications de configuration basées sur la taille
Les changements de configuration basés sur la taille peuvent se produire à tout moment et sont plus susceptibles de se produire lorsque votre application s'exécute sur un appareil à grand écran sur lequel les utilisateurs peuvent activer le mode multifenêtre. Ils s'attendent à ce que votre application fonctionne correctement dans cet environnement.
Il existe deux types généraux de modifications de taille : importantes et non importantes. Une modification de taille importante se produit lorsqu'un ensemble différent de ressources alternatives s'applique à la nouvelle configuration en raison d'une différence de taille d'écran, comme la largeur, la hauteur ou la plus petite largeur. Ces ressources incluent celles que l'application définit elle-même et celles de l'une de ses bibliothèques.
Limiter la recréation d'activité pour les modifications de configuration en fonction de la taille
Lorsque vous désactivez la recréation d'Activity pour les modifications de configuration en fonction de la taille, le système ne recrée pas l'Activity. En revanche, il reçoit un appel à Activity.onConfigurationChanged(). Toutes les vues associées reçoivent un appel à View.onConfigurationChanged().
La recréation de Activity est désactivée pour les modifications de configuration basées sur la taille lorsque vous avez android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" dans votre fichier manifeste.
Autoriser la recréation d'activité pour les modifications de configuration en fonction de la taille
Sur Android 7.0 (niveau d'API 24) et versions ultérieures, la recréation de Activity n'a lieu pour les changements de configuration basés sur la taille que si le changement de taille est important. Lorsque le système ne recrée pas d'Activity en raison d'une taille insuffisante, il peut appeler Activity.onConfigurationChanged() et View.onConfigurationChanged() à la place.
Il existe quelques mises en garde concernant les rappels Activity et View lorsque Activity n'est pas recréé :
- Sur Android 11 (niveau d'API 30) à Android 13 (niveau d'API 33),
Activity.onConfigurationChanged()n'est pas appelé. - Il existe un problème connu qui empêche parfois l'appel de
View.onConfigurationChanged()sur Android 12L (niveau d'API 32) et les premières versions d'Android 13 (niveau d'API 33). Pour en savoir plus, consultez ce problème public. Ce problème a été résolu dans les versions ultérieures d'Android 13 et dans Android 14.
Pour le code qui dépend de l'écoute des modifications de configuration basées sur la taille, nous vous recommandons d'utiliser un utilitaire View avec un View.onConfigurationChanged() remplacé au lieu de vous fier à la recréation Activity ou à Activity.onConfigurationChanged().