Actualités des produits

Nouveautés de la version de décembre 2025 de Jetpack Compose

Temps de lecture : 6 min
Nick Butcher
Responsable produit

Aujourd'hui, la version de décembre 2025 de Jetpack Compose est stable. Elle contient la version 1.10 des modules Compose de base et la version 1.4 de Material 3 (consultez le mapping BOM complet), qui ajoutent de nouvelles fonctionnalités et améliorent considérablement les performances.

Pour utiliser la version d'aujourd'hui, mettez à niveau votre version de Compose BOM vers 2025.12.00 :

implementation(platform("androidx.compose:compose-bom:2025.12.00"))

Améliorations des performances

Nous savons que les performances d'exécution de votre application sont extrêmement importantes pour vous et vos utilisateurs. C'est pourquoi les performances ont été une priorité majeure pour l'équipe Compose. Cette version apporte plusieurs améliorations. Pour en profiter, il vous suffit de passer à la dernière version. Nos benchmarks de défilement internes montrent que Compose correspond désormais aux performances que vous obtiendriez en utilisant des vues :

janky.png

Benchmark des performances de défilement comparant les vues et Jetpack Compose dans différentes versions de Compose

Composition pouvant être mise en pause dans la prélecture différée

La composition pouvant être mise en pause dans le préchargement différé est désormais activée par défaut. Il s'agit d'un changement fondamental dans la façon dont le runtime Compose planifie les tâches. Il est conçu pour réduire considérablement les saccades lors de charges de travail d'UI importantes.

Auparavant, une fois qu'une composition avait commencé, elle devait être exécutée jusqu'à la fin. Si une composition était complexe, cela pouvait bloquer le thread principal pendant plus d'un frame, ce qui entraînait le blocage de l'UI. Avec la composition pouvant être mise en pause, le runtime peut désormais "mettre en pause" son travail s'il manque de temps et le reprendre dans le frame suivant. Cette méthode est particulièrement efficace lorsqu'elle est utilisée avec la prélecture de mise en page différée pour préparer les frames à l'avance. Les API CacheWindow de mise en page différée introduites dans Compose 1.9 sont un excellent moyen de précharger plus de contenu et de bénéficier de la composition pouvant être mise en pause pour obtenir des performances d'UI beaucoup plus fluides.

pausable.gif

La composition pouvant être mise en pause combinée à la prélecture différée permet de réduire les saccades

Nous avons également optimisé les performances ailleurs, en améliorant Modifier.onPlaced, Modifier.onVisibilityChanged et d'autres implémentations de modificateurs. Nous continuerons d'investir dans l'amélioration des performances de Compose.

Nouvelles fonctionnalités

Fidélisation

Compose propose un certain nombre d'API pour conserver et gérer l'état tout au long des différents cycles de vie. Par exemple, remember conserve l'état lors des recompositions, et rememberSavable/rememberSerializable pour le conserver lors de la recréation d'une activité ou d'un processus. retain est une nouvelle API qui se situe entre ces API. Elle vous permet de conserver les valeurs lors des modifications de configuration sans les sérialiser, mais pas en cas d'arrêt du processus. Comme retain ne sérialise pas votre état, vous pouvez conserver des objets tels que des expressions lambda, des flux et des objets volumineux comme des bitmaps, qui ne peuvent pas être facilement sérialisés. Par exemple, vous pouvez utiliser retain pour gérer un lecteur multimédia (tel qu'ExoPlayer) afin de vous assurer que la lecture multimédia n'est pas interrompue par un changement de configuration.

@Composable

fun MediaPlayer() {

    val applicationContext = LocalContext.current.applicationContext

    val exoPlayer = retain { ExoPlayer.Builder(applicationContext).apply { ... }.build() }

    ...

}

Nous tenons à remercier la communauté AndroidDev (en particulier l'équipe Circuit) qui a influencé et contribué à la conception de cette fonctionnalité.

Material 1.4

La version 1.4.0 de la bibliothèque material3 ajoute un certain nombre de nouveaux composants et améliorations :

centered-hero-carousel.webp

Carrousel hero horizontal centré

Notez que les API Material 3 Expressive continuent d'être développées dans les versions alpha de la bibliothèque material3. Pour en savoir plus, regardez cette conférence récente :

Nouvelles fonctionnalités d'animation

Nous continuons à développer nos API d'animation, y compris les mises à jour pour personnaliser les animations d'éléments partagés.

Éléments partagés dynamiques

Par défaut, les animations sharedElement() et sharedBounds() tentent d'animer

La mise en page change chaque fois qu'une clé correspondante est trouvée dans l'état cible. Toutefois, vous pouvez désactiver cette animation de manière dynamique en fonction de certaines conditions, telles que le sens de la navigation ou l'état actuel de l'UI.

Pour contrôler si la transition entre éléments partagés a lieu, vous pouvez désormais personnaliser le SharedContentConfig transmis à rememberSharedContentState(). La propriété isEnabled détermine si l'élément partagé est actif.

SharedTransitionLayout {

        val transition = updateTransition(currentState)

        transition.AnimatedContent { targetState ->

            // Create the configuration that depends on state changing.

            fun animationConfig() : SharedTransitionScope.SharedContentConfig {

                return object : SharedTransitionScope.SharedContentConfig {

                    override val SharedTransitionScope.SharedContentState.isEnabled: Boolean

                        get() =

                            // determine whether to perform a shared element transition

                }

            }

}

Pour en savoir plus, consultez la documentation.

Modifier.skipToLookaheadPosition()

Un nouveau modificateur, Modifier.skipToLookaheadPosition(), a été ajouté dans cette version. Il permet de conserver la position finale d'un composable lors de l'exécution d'animations d'éléments partagés. Cela permet d'effectuer des transitions telles que l'animation de type "dévoilement", comme on peut le voir dans l'exemple Androidify avec le dévoilement progressif de la caméra. Pour en savoir plus, regardez cette vidéo :

Vitesse initiale dans les transitions d'éléments partagés

Cette version ajoute une nouvelle API de transition d'éléments partagés, prepareTransitionWithInitialVelocity, qui vous permet de transmettre une vitesse initiale (par exemple, à partir d'un geste) à une transition d'éléments partagés :

Modifier.fillMaxSize()

    .draggable2D(

        rememberDraggable2DState { offset += it },

        onDragStopped = { velocity ->

            // Set up the initial velocity for the upcoming shared element

            // transition.

            sharedContentStateForDraggableCat

                ?.prepareTransitionWithInitialVelocity(velocity)

            showDetails = false

        },

    )
fling-shared.gif

Transition d'élément partagé qui commence avec une vitesse initiale à partir d'un geste

Transitions voilées

EnterTransition et ExitTransition définissent la façon dont un composable AnimatedVisibility/AnimatedContent apparaît ou disparaît. Une nouvelle option expérimentale de voile vous permet de spécifier une couleur pour voiler ou masquer le contenu. Par exemple, vous pouvez faire apparaître ou disparaître une couche noire semi-opaque sur le contenu :

veil_2.gif

Contenu animé voilé : notez le voile semi-opaque (ou la toile) sur le contenu de la grille pendant l'animation.

AnimatedContent(

    targetState = page,

    modifier = Modifier.fillMaxSize().weight(1f),

    transitionSpec = {

        if (targetState > initialState) {

            (slideInHorizontally { it } togetherWith

                    slideOutHorizontally { -it / 2 } + veilOut(targetColor = veilColor))

        } else {

            slideInHorizontally { -it / 2 } +

                    unveilIn(initialColor = veilColor) togetherWith slideOutHorizontally { it }

        }

    },

) { targetPage ->

    ...

}

Modifications à venir

Obsolescence de Modifier.onFirstVisible

Compose 1.9 a introduit Modifier.onVisibilityChanged et Modifier.onFirstVisible. Après examen de vos commentaires, il est apparu que le contrat de Modifier.onFirstVisible ne pouvait pas être respecté de manière déterministe, en particulier lorsqu'un élément devient visible pour la première fois. Par exemple, une mise en page Lazy peut supprimer les éléments qui défilent hors de la fenêtre d'affichage, puis les recomposer s'ils reviennent dans la vue. Dans ce cas, le rappel onFirstVisible se déclenchera à nouveau, car il s'agit d'un élément nouvellement composé. Un comportement similaire se produirait également lors du retour à un écran précédemment visité contenant onFirstVisible. Par conséquent, nous avons décidé d'abandonner ce modificateur dans la prochaine version de Compose (1.11) et nous vous recommandons de migrer vers onVisibilityChanged. Pour en savoir plus, consultez la documentation.

Répartition des coroutines dans les tests

Nous prévoyons de modifier le dispatch de coroutine dans les tests afin d'améliorer la fiabilité des tests et de détecter davantage de problèmes. Actuellement, les tests utilisent UnconfinedTestDispatcher, qui diffère du comportement de production. Par exemple, les effets peuvent s'exécuter immédiatement au lieu d'être mis en file d'attente. Dans une prochaine version, nous prévoyons d'introduire une nouvelle API qui utilise StandardTestDispatcher par défaut pour correspondre aux comportements de production. Vous pouvez essayer le nouveau comportement dès maintenant dans la version 1.10 :

@get:Rule // also createAndroidComposeRule, createEmptyComposeRule

val rule = createComposeRule(effectContext = StandardTestDispatcher())

L'utilisation de StandardTestDispatcher met les tâches en file d'attente. Vous devez donc utiliser des mécanismes de synchronisation tels que composeTestRule.waitForIdle() ou composeTestRule.runOnIdle(). Si votre test utilise runTest, vous devez vous assurer que runTest et votre règle Compose partagent la même instance StandardTestDispatcher pour la synchronisation.

// 1. Create a SINGLE dispatcher instance

val testDispatcher = StandardTestDispatcher()



// 2. Pass it to your Compose rule

@get:Rule

val composeRule = createComposeRule(effectContext = testDispatcher)



@Test

// 3. Pass the *SAME INSTANCE* to runTest

fun myTest() = runTest(testDispatcher) {

    composeRule.setContent { /* ... */ }

}

Outils

Les excellentes API méritent d'excellents outils. Android Studio a récemment ajouté plusieurs fonctionnalités pour les développeurs Compose :

Pour voir ces outils en action, regardez cette démonstration récente :

À vos claviers !

Nous continuons d'investir dans Jetpack Compose pour vous fournir les API et les outils dont vous avez besoin pour créer des interfaces utilisateur esthétiques et riches. Vos commentaires sont importants. N'hésitez pas à nous les envoyer sur ces modifications ou sur ce que vous aimeriez voir ensuite dans notre outil de suivi des problèmes.

Écrit par :

Lire la suite