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 par rapport au mode clair
- Disponibilité du clavier
La plupart de ces modifications de configuration sont dues à une interaction de l'utilisateur. Par exemple, la rotation ou le pliage de l'appareil modifie la quantité d'espace disponible sur l'écran 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 dédié lorsqu'ils changent.
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()
, et cette nouvelle instance Activity
est initialisée avec la nouvelle configuration mise à jour. Cela signifie également que le système recrée également l'UI avec la nouvelle configuration.
Le comportement de recréation aide votre application à s'adapter aux nouvelles configurations en la rechargeant automatiquement avec d'autres ressources 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"
, comme défini dans un fichier XML de mise en page. Lorsque la vue est créée, elle définit le texte 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 avec la valeur correcte en fonction de la nouvelle langue.
La recréation efface également tout état conservé en tant que champs dans le Activity
ou dans l'un de ses Fragment
, View
ou autres objets contenus. En effet, la recréation de Activity
crée une instance entièrement nouvelle de Activity
et de l'UI. De plus, l'ancienne Activity
n'est plus visible ni valide. Par conséquent, toutes les références restantes à celle-ci ou aux objets qu'elle contient 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 préservé. Si un utilisateur remplit un formulaire et ouvre une autre application en mode multifenêtre pour consulter des informations, l'expérience utilisateur est mauvaise s'il revient à un formulaire effacé ou à un autre emplacement de l'application. En tant que développeur, vous devez proposer une expérience utilisateur cohérente via des modifications de configuration et la recréation d'activités.
Pour vérifier si l'état est conservé dans votre application, vous pouvez effectuer des actions qui entraînent des modifications de configuration à la fois 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
- Redimensionnement de l'application en mode multifenêtre ou dans une fenêtre de format libre
- Plier un appareil pliable avec plusieurs écrans
- Modifier 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 d'accueil
Il existe trois principales approches que vous pouvez suivre pour conserver l'état pertinent via la recréation de Activity
. Le type à utiliser dépend du type d'état que vous souhaitez conserver:
- 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
. - Objets conservés tels que les instances
ViewModel
pour gérer l'état lié à l'UI en mémoire lorsque l'utilisateur utilise activement l'application. - État d'instance enregistré pour gérer l'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 de chacune de ces méthodes et connaître les cas d'utilisation appropriés, consultez la section Enregistrer les états de l'UI.
Limiter la recréation d'activité
Vous pouvez empêcher la recréation automatique d'activités pour certaines modifications de configuration.
La recréation de Activity
entraîne la recréation de l'UI entière et de tous les objets dérivés de Activity
. Vous pouvez avoir de bonnes raisons de ne pas le faire. Par exemple, votre application n'aura peut-être pas besoin de mettre à jour les ressources lors d'un changement de configuration spécifique, ou vous pourriez rencontrer une limitation des 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 redémarrer votre activité.
Pour désactiver la recréation d'activités pour des modifications de configuration particulières, 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 couleur dynamique 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 pour laquelle vous avez désactivé la recréation de Activity
se produit, 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 interface utilisateur 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 pour téléviseur 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 pouvoir 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, si vous désactivez la recréation de Activity
pour toutes les modifications de configuration lorsque 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 modulables qui lisent LocalConfiguration.current
sont recomposées. Pour en savoir plus sur le fonctionnement des variables locales de composition, consultez la section Données à champ d'application local avec CompositionLocal.
Exemple
Dans l'exemple suivant, un composable affiche une date avec un format spécifique.
Le composable réagit aux modifications de configuration des paramètres régionaux 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
.
Changements de configuration: concepts clés et bonnes pratiques
Voici les concepts clés que vous devez connaître lorsque vous travaillez sur des modifications de configuration:
- Configurations:les configurations de l'appareil définissent la façon dont l'UI s'affiche pour l'utilisateur, comme 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 de l'interaction de l'utilisateur. 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 deActivity
par 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
Activity
:la recréation deActivity
entraîne la destruction de l'ancienne instanceActivity
et 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. - État:l'état de l'ancienne instance
Activity
n'est pas présent dans la nouvelle instanceActivity
, car il s'agit de deux instances d'objets différentes. Conservez l'état de l'application et de l'utilisateur, comme décrit dans la section Enregistrer les états de l'UI. - Désactivation:la désactivation de la recréation d'une activité pour un type de modification de configuration est une optimisation potentielle. Pour cela, votre application doit être correctement mise à jour en réaction à la nouvelle configuration.
Pour offrir une bonne expérience utilisateur, suivez les bonnes pratiques suivantes:
- Préparez-vous à des modifications de configuration fréquentes:ne partez pas du principe que les modifications de configuration sont rares ou qu'elles n'arrivent jamais, quel que soit le niveau d'API, le facteur de forme ou la boîte à outils d'UI. Lorsqu'un utilisateur provoque une modification de configuration, il s'attend à ce que les applications soient mises à jour et continuent de fonctionner correctement avec la nouvelle configuration.
- Conserver l'état:ne perdez pas 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
Activity
comme raccourci pour éviter la perte d'état. Si vous désactivez la recréation d'activité, vous devez tenir la promesse de gérer le changement. Vous pouvez toujours perdre l'état en raison de la recréation deActivity
à partir d'autres modifications de configuration, de l'arrêt du processus ou de 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. - N'évitez pas les modifications de configuration:n'imposez pas de restrictions sur l'orientation, le format ou la redimensionnabilité pour éviter les modifications de configuration et la recréation de
Activity
. Cela a un impact négatif sur les utilisateurs qui souhaitent utiliser votre application de la manière qui leur convient le mieux.
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 probables 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. Un changement de taille significatif est celui où un ensemble différent de ressources alternatives s'applique à la nouvelle configuration en raison d'une différence de taille d'écran, telle que 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 basées sur la taille, le système ne recrée pas 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 android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout"
est présent 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) ou version ultérieure, la recréation de Activity
seulement se produit pour les modifications de configuration basées sur la taille si la modification de taille est importante. Lorsque le système ne recrée pas un Activity
en raison d'une taille insuffisante, il peut appeler Activity.onConfigurationChanged()
et View.onConfigurationChanged()
à la place.
Certaines mises en garde doivent être observées concernant les rappels Activity
et View
lorsque le 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 où
View.onConfigurationChanged()
peut ne pas être appelé dans certains cas 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 d'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()
écrasé au lieu de vous appuyer sur la recréation de Activity
ou sur Activity.onConfigurationChanged()
.