Mode sauté fort

Le mode de saut forcé est disponible dans le compilateur Compose. Lorsqu'elle est activée, elle modifie le comportement du compilateur de deux manières :

  • Les composables avec des paramètres instables deviennent skippables.
  • Les lambdas avec des captures instables sont mémorisés.

Activer le mode de désactivation renforcée

Le mode de saut strict est activé par défaut dans Kotlin 2.0.20.

Pour activer le mode de saut renforcé pour un module Gradle dans une version antérieure à la version 2.0.20, incluez l'option suivante dans le bloc composeCompiler de votre configuration Gradle :

android { ... }

composeCompiler {
   enableStrongSkippingMode = true
}

Désactivation des composables

Le mode de saut renforcé assouplit certaines des règles de stabilité normalement appliquées par le compilateur Compose en ce qui concerne le saut et les fonctions composables. Par défaut, le compilateur Compose marque une fonction composable comme pouvant être ignorée si tous ses arguments ont des valeurs stables. Le mode de désactivation renforcée modifie ce comportement.

Lorsque le mode d'omission stricte est activé, toutes les fonctions composables redémarrables peuvent être ignorées. Cela s'applique, qu'ils aient ou non des paramètres instables. Les fonctions composables non redémarrables restent non ignorables.

Quand ignorer

Pour déterminer s'il faut ignorer un composable lors de la recomposition, Compose compare la valeur de chaque paramètre à ses valeurs précédentes. Le type de comparaison dépend de la stabilité du paramètre.

  • Les paramètres instables sont comparés à l'aide de l'égalité des instances (===).
  • Les paramètres stables sont comparés à l'aide de l'égalité d'objet (Object.equals()).

Si tous les paramètres répondent à ces exigences, Compose ignore le composable lors de la recomposition.

Vous pouvez souhaiter qu'un composable désactive le mode d'omission renforcé. Par exemple, vous pouvez souhaiter un composable redémarrable, mais non ignorable. Dans ce cas, utilisez l'annotation @NonSkippableComposable.

@NonSkippableComposable
@Composable
fun MyNonSkippableComposable {}

Annoter des classes comme stables

Si vous souhaitez qu'un objet soit comparé à l'aide de l'égalité d'objet (Object.equals()) au lieu de l'égalité d'instance (===), continuez à annoter la classe donnée avec @Stable ou @Immutable.

Tenez compte des compromis suivants avant d'ajouter @Stable ou @Immutable :

  • Les classes avec des propriétés stables dans les modules Compose sont déjà stables : une classe avec des propriétés val de types stables dans un module compilé avec le compilateur Compose est automatiquement déduite comme stable et utilise .equals() sans avoir besoin de @Immutable ou @Stable.
  • N'annotez les classes qu'avec des vérifications .equals() peu coûteuses : ajoutez @Stable ou @Immutable lorsque le compilateur ne peut pas déduire la stabilité (comme les classes de modules non Compose) et que de nouvelles instances avec des valeurs identiques sont fréquemment allouées, à condition que la vérification .equals() de la classe soit peu coûteuse.
  • Soyez prudent lorsque vous annotez des modèles avec des collections : l'ajout de @Stable ou de @Immutable aux modèles contenant des collections (ou le remplacement de List par ImmutableList) entraîne la comparaison de chaque élément de la collection avec .equals() à chaque recomposition. Pour les collections ou les modèles volumineux utilisés dans les mises en page différées (LazyColumn, LazyRow, LazyGrid), comparer chaque élément peut être plus lent que d'utiliser l'égalité d'instance (===) ou de recomposer directement.

Mémoïsation lambda

Le mode de désactivation renforcée permet également une meilleure mémorisation des lambdas dans les composables. Lorsque la désactivation renforcée est activée, chaque lambda d'une fonction composable est automatiquement mémorisé.

Exemples

Pour mémoriser les lambdas dans les composables lors de l'utilisation du mode de saut strict, le compilateur encapsule votre lambda avec un appel remember. Il est associé aux captures de la lambda.

Prenons l'exemple d'une fonction lambda comme celle-ci :

@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = {
        use(unstableObject)
        use(stableObject)
    }
}

Lorsque la désactivation renforcée est activée, le compilateur mémorise le lambda en l'encapsulant dans un appel remember :

@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = remember(unstableObject, stableObject) {
        {
            use(unstableObject)
            use(stableObject)
        }
    }
}

Les clés suivent les mêmes règles de comparaison que les fonctions composables. L'environnement d'exécution compare les clés instables à l'aide de l'égalité d'instance. Il compare les clés stables à l'aide de l'égalité des objets.

Mémorisation et recomposition

Cette optimisation augmente considérablement le nombre de composables que l'environnement d'exécution ignore lors de la recomposition. Sans mémoïsation, l'environnement d'exécution est beaucoup plus susceptible d'allouer un nouveau lambda à tout composable qui accepte un paramètre lambda lors de la recomposition. Par conséquent, le nouveau lambda comporte des paramètres qui ne sont pas égaux à la dernière composition. Cela entraîne une recomposition.

Éviter la mémorisation

Si vous avez une lambda que vous ne souhaitez pas mémoriser, utilisez l'annotation @DontMemoize.

val lambda = @DontMemoize {
    ...
}

Taille de l'APK

Lorsqu'ils sont compilés, les composables ignorables génèrent plus de code que les composables non ignorables. Lorsque le mode d'omission stricte est activé, le compilateur marque presque tous les composables comme pouvant être ignorés et encapsule tous les lambdas dans un remember{...}. Par conséquent, l'activation du mode de désactivation renforcée a un impact très faible sur la taille de l'APK de votre application.

L'activation de l'omission forcée dans Now in Android a augmenté la taille de l'APK de 4 ko. La différence de taille dépend en grande partie du nombre de composables auparavant non ignorables qui étaient présents dans l'application, mais elle devrait être relativement mineure.