Jetpack Compose est un toolkit déclaratif moderne pour construire des interfaces Android en Kotlin. Le développeur décrit l'UI via des fonctions composable, et le toolkit redessine automatiquement uniquement les parties modifiées. Selon Android Developers (2026), Jetpack Compose fonctionne sous Android 5.0 (API 21) et supérieur, prend en charge Material Design 3 et atteint 120 FPS sur les appareils de milieu de gamme grâce à son propre système de Recomposition — un algorithme diff intelligent qui met à jour uniquement les widgets modifiés.
Points clés
Jetpack Compose est un framework déclaratif de Google pour construire des interfaces utilisateur Android, annoncé en 2019 et ayant atteint sa version stable en 2021. Contrairement à l'ancien View System (layout XML + Activity/Fragment), Compose utilise des fonctions Kotlin annotées — @Composable. L'interface est décrite entièrement en Kotlin : il n'y a pas de séparation entre XML et code. Cela a éliminé la classe d'erreurs liées aux IDs incompatibles dans XML et Kotlin (type-safe synthetic n'aidait pas lors du refactoring).
Compose est construit sur son propre système de rendu — Canvas, non lié à la hiérarchie View. Chaque Composable se dessine directement sur Canvas, en contournant onMeasure/onDraw du View System. Cela offre un gain de performance sur les écrans complexes : dans les tests de Google (2023), un écran Compose avec 200 éléments s'est rendu 40% plus rapidement qu'un écran similaire sur RecyclerView + ViewHolder.
Compose nécessite minSdk 21 (Android 5.0) et Kotlin 1.9+. Le BOM (Bill of Materials) de Compose synchronise les versions de toutes les bibliothèques Compose. Le framework est compatible avec le code View System existant : Compose s'intègre via ComposeView dans les layouts XML, et les View anciennes via AndroidView dans la hiérarchie Compose. Selon Google Play Console (2025), Android 5.0+ couvre 97% des appareils actifs, donc la compatibilité n'est pas une limitation pour la plupart des projets.
@Composable est une annotation qui transforme une fonction Kotlin ordinaire en un bloc de construction d'UI. Une fonction Composable décrit à quoi devrait ressembler un fragment d'interface — texte, bouton, liste. Au lieu de retourner une valeur, la fonction émet des composants UI dans la composition. Cela ressemble à un générateur : chaque fonction ajoute des éléments à l'écran lors de l'appel.
@Composable
fun ProfileCard(name: String, avatarUrl: String) {
Card(
modifier = Modifier.fillMaxWidth().padding(16.dp),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surface
)
) {
Row(verticalAlignment = Alignment.CenterVertically) {
AsyncImage(
model = avatarUrl,
contentDescription = "Avatar",
modifier = Modifier.size(48.dp).clip(CircleShape)
)
Spacer(Modifier.width(12.dp))
Text(
text = name,
style = MaterialTheme.typography.titleMedium
)
}
}
}
La fonction ProfileCard prend des paramètres (name, avatarUrl) et émet Card → Row → AsyncImage + Text. Composition est l'arbre des composants émis en un seul passage. Si les paramètres n'ont pas changé, Compose saute l'appel de fonction (recomposition skip). Si seul name a changé, seul Text sera appelé, les autres éléments ne seront pas redessinés. Cette recomposition intelligente est l'avantage clé de performance de Compose par rapport à l'optimisation manuelle du View System.
Les fonctions Composable utilisent activement les slots — trailing lambda, content: @Composable (() -> Unit). Cela permet de créer des conteneurs : Card, Column, Row acceptent une lambda content, et le contenu est inséré dans le slot. La Slot API a remplacé les attributs XML comme android:layout_gravity — maintenant le positionnement des éléments enfants est défini par du code Kotlin à l'intérieur du bloc de contenu.
State dans Compose est toute valeur qui peut changer au fil du temps. Lorsque l'état change, Compose planifie la recomposition pour tous les composants qui lisent cet état. Le mécanisme ressemble aux hooks React : mutableStateOf retourne MutableState<T>, la lecture de .value abonne automatiquement la composition courante aux changements.
@Composable
fun CounterExample() {
var count by remember { mutableStateOf(0) }
Column(modifier = Modifier.padding(16.dp)) {
Text("Cliqué : $count")
Button(onClick = { count++ }) {
Text("Incrémenter")
}
}
}
@Composable
fun UserScreen(viewModel: UserViewModel) {
val userName by viewModel.userName.collectAsState()
Text("Utilisateur : $userName")
}
remember conserve la valeur entre les recompositions — sinon mutableStateOf serait recréé à chaque mise à jour d'UI. collectAsState() convertit StateFlow du ViewModel en un état compatible Compose. Recommandation — utilisez ViewModel avec StateFlow pour l'état au niveau de l'écran, et mutableStateOf pour l'état local (par exemple, carte dépliée). Cette séparation suit le principe des composants intelligents/muets.
State Hoisting est un modèle de remontée de l'état d'un composant enfant vers le parent. Le parent transmet la valeur et un callback via des paramètres, l'enfant appelle le callback lors du changement. Le parent détient le mutableStateOf, l'enfant seulement les paramètres. Cela rend le composant réutilisable et testable : le même TextField peut être utilisé avec n'importe quelle source de données.
Modifier est un objet qui décrit les transformations du Composable : taille, marges, fond, gestion des clics, animation, défilement. Les modificateurs sont appliqués via une chaîne d'appels : Modifier.fillMaxWidth().padding(16.dp).background(Color.Blue).clickable { }. Chaque appel retourne un nouveau Modifier avec la propriété ajoutée — sans mutation de l'objet original.
L'ordre des modificateurs est important. Modifier.padding(16.dp).background(Color.Blue) colore la zone avec la marge. Modifier.background(Color.Blue).padding(16.dp) colore le rectangle intérieur, et la marge reste transparente. La mécanique ressemble au modèle de boîte CSS : padding d'abord → background fonctionne comme margin + background ; background d'abord → padding fonctionne comme background + marge intérieure. Le développeur doit simplement retenir : padding d'abord = marge externe, padding après = marge interne.
Si les modificateurs intégrés ne suffisent pas, on crée un modificateur personnalisé via Modifier.composed { ... } ou Modifier.then(). À l'intérieur d'un modificateur personnalisé, on peut utiliser des mesures de layout (Modifier.layout { measurable, constraints -> ... }), du dessin (Modifier.drawWithContent { ... }), des gestes (Modifier.pointerInput { ... }). Exemple : un modificateur pour une animation pulsante au clic — mesure la taille, au clic lance une animation d'échelle via animateFloatAsState.
Pour les animations, Compose fournit animate*AsState (animateFloatAsState, animateColorAsState, animateDpAsState) — les valeurs s'animent entre l'état ancien et le nouveau lors du changement. Pour les animations d'entrée/sortie — AnimatedVisibility et AnimatedContent avec des transitions intégrées (fade, slide, expand). Toutes les animations fonctionnent sur la couche graphique sans déclencher de composition inutile.
Les fonctions Composable ne doivent pas effectuer d'effets secondaires directement (requêtes réseau, minuteries, abonnements) — elles sont appelées à chaque recomposition, ce qui entraînerait des requêtes en double. Pour les effets secondaires, Compose fournit une famille de fonctions Effect : LaunchedEffect lance une coroutine à l'entrée dans la composition et l'annule à la sortie, DisposableEffect — pour les ressources nécessitant un nettoyage explicite (capteurs, BroadcastReceiver).
@Composable
fun SensorReader() {
val context = LocalContext.current
var sensorValue by remember { mutableStateOf(0f) }
DisposableEffect(Unit) {
val sensor = registerSensorListener(context) { value ->
sensorValue = value
}
onDispose {
unregisterSensorListener(sensor)
}
}
Text("Valeur : $sensorValue")
}
@Composable
fun UserGreeting(userId: String) {
LaunchedEffect(userId) {
val profile = api.fetchProfile(userId)
// mise à jour d'état
}
}
LaunchedEffect(userId) redémarre si userId change — la coroutine précédente est annulée, une nouvelle est lancée avec le nouveau userId. Cela élimine la gestion manuelle de l'annulation des requêtes. DisposableEffect(Unit) — un effet avec une clé fixe Unit, se déclenche à l'entrée dans la composition et appelle onDispose à la sortie. SensorReader enregistre un écouteur et se désabonne en quittant l'écran — sans risque de fuite.
Si une coroutine doit être lancée non pas à l'entrée dans la composition mais sur un événement (clic sur un bouton), on utilise rememberCoroutineScope(). Il retourne un CoroutineScope lié au cycle de vie du Composable, sans nécessiter de DisposableEffect. Exemple : lancer une requête réseau au clic sur un bouton — scope.launch { viewModel.loadData() }.
Choisir entre Compose et View System est la principale question architecturale pour les développeurs Android en 2026. Les deux technologies sont supportées par Google, mais Compose est la direction principale dans laquelle Google investit des ressources. View System ne reçoit que des corrections critiques et n'évolue pas. La différence se manifeste dans la syntaxe, la gestion d'état, les performances et le temps de développement.
| Aspect | Jetpack Compose | View System |
|---|---|---|
| Description de l'UI | Fonctions Kotlin @Composable | Layout XML + Activity/Fragment |
| État | mutableStateOf, StateFlow, redessin automatique | findViewById, manuel : setText, notifyDataSetChanged |
| Performance | Recomposition intelligente, rendu Canvas | Hiérarchie View, measure/layout/draw |
| Animations | animate*AsState, AnimatedVisibility, intégrées | ValueAnimator, ObjectAnimator, Transition |
| Compatibilité | minSdk 21, ponts ComposeView/AndroidView | Toutes versions, toute |
| Taille APK | +3–5 Mo pour Compose | Sans surcoût |
Pour les nouveaux projets, Google recommande Jetpack Compose comme standard de développement d'UI. View System reste pour la maintenance du code écrit avant 2021, et pour les cas où la taille minimale de l'APK est critique (par exemple, pour les marchés émergents avec des appareils d'entrée de gamme). Compose réduit le volume de code UI de 30 à 50% par rapport à View System grâce à sa syntaxe déclarative et ses animations intégrées.
Questions fréquentes
Oui, via ComposeView dans le layout XML. Ajoutez la dépendance Compose et encapsulez l'écran ou une partie de celui-ci dans ComposeView { MyComposable() }. La migration se fait écran par écran.
La raison est que l'état est remonté trop haut ou que des objets mutables sont utilisés. Correction : derivedStateOf pour les données dérivées et remember pour les références stables.
Utilisez LazyColumn (analogue à RecyclerView). Les éléments sont créés et réutilisés au fur et à mesure du défilement. Pour les listes complexes avec différents types de cellules — LazyColumn { items(items, key = { it.id }) { ... } }.
Non, vous pouvez commencer directement avec Compose. La connaissance de View System aide pour la maintenance du code legacy, mais Compose est un écosystème indépendant avec sa propre documentation et ses propres modèles.
Oui, Material 3 est le thème standard de Compose depuis 2023. Il s'ajoute via implementation("androidx.compose.material3:material3"). Material 2 est considéré comme obsolète.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi