Actualités sur les 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 (voir le mappage complet de la BOM), et ajoute de nouvelles fonctionnalités et des améliorations majeures des performances.

Pour utiliser la version d'aujourd'hui, mettez à niveau votre version de la BOM Compose 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 l'équipe Compose a fait des performances une priorité majeure. Cette version apporte un certain nombre d'améliorations, et vous pouvez toutes les obtenir en passant simplement à la dernière version. Nos benchmarks de défilement internes montrent que Compose correspond désormais aux performances que vous obtiendriez si vous utilisiez 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 la prélecture différée est désormais activée par défaut. Il s'agit d'un changement fondamental dans le fonctionnement de la planification de l'exécution de Compose, conçu pour réduire considérablement les à-coups lors des charges de travail d'interface utilisateur importantes.

Auparavant, une fois qu'une composition avait commencé, elle devait s'exécuter jusqu'à la fin. Si une composition était complexe, cela pouvait bloquer le thread principal pendant plus d'une seule image, ce qui entraînait le gel de l'interface utilisateur. Avec la composition pouvant être mise en pause, l'exécution peut désormais "mettre en pause" son travail si elle manque de temps et le reprendre dans l'image suivante. Cela est particulièrement efficace lorsqu'il est utilisé avec la prélecture différée de la mise en page pour préparer les images à l'avance. Les API Lazy layout CacheWindow introduites dans Compose 1.9 sont un excellent moyen de précharger plus de contenu et de bénéficier d'une composition pouvant être mise en pause pour obtenir des performances d'interface utilisateur 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 à-coups

Nous avons également optimisé les performances ailleurs, avec des améliorations apportées à 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

Retain

Compose propose un certain nombre d'API pour conserver et gérer l'état sur différents cycles de vie. Par exemple, remember conserve l'état sur les compositions, et rememberSavable/rememberSerializable pour conserver l'état sur la recréation d'une activité ou d'un processus.retain est une nouvelle API qui se situe entre ces API, ce qui vous permet de conserver les valeurs lors des modifications de configuration sans être sérialisé, mais pas lors de l'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 tels que 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 une modification 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 de héros centré horizontalement

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

Nouvelles fonctionnalités d'animation

Nous continuons de développer nos API d'animation, y compris des 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 les

modifications de mise en page 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'interface utilisateur.

Pour contrôler si la transition d'élément partagé se produit, 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 conserve 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 "révélation", comme on peut le voir dans l'exemple Androidify avec la révélation progressive de l'appareil photo. Pour en savoir plus, regardez cette astuce 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éments partagés qui commence par une vitesse initiale à partir d'un geste

Transitions voilées

EnterTransition et ExitTransition définissent comment un AnimatedVisibility/AnimatedContent composable apparaît ou disparaît. Une nouvelle option de voile expérimentale 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 le masque) 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

Abandon de Modifier.onFirstVisible

Compose 1.9 a introduit Modifier.onVisibilityChanged et Modifier.onFirstVisible. Après avoir examiné vos commentaires, il est devenu évident 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 différée peut supprimer les éléments qui défilent hors de la fenêtre d'affichage, puis les composer à nouveau 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 lorsque vous revenez à 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 la répartition des coroutines dans les tests afin d'améliorer la fiabilité des tests et de détecter davantage de problèmes. Actuellement, les tests utilisent le 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 mettra 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 API de qualité méritent des outils de qualité. 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 :

Bonne composition

Nous continuons d'investir dans Jetpack Compose pour vous fournir les API et les outils dont vous avez besoin pour créer des UI esthétiques et riches. Nous apprécions vos commentaires. N'hésitez donc pas à nous faire part de vos commentaires sur ces modifications ou sur ce que vous aimeriez voir ensuite dans notre outil de suivi des problèmes.

Écrit par :

Lire la suite