Jetpack Compose is een moderne declaratieve toolkit voor het bouwen van Android-interfaces in Kotlin. De ontwikkelaar beschrijft de UI via composable functies en de toolkit hertekent automatisch alleen de gewijzigde delen. Volgens Android Developers (2026), werkt Jetpack Compose op Android 5.0 (API 21) en hoger, ondersteunt Material Design 3 en bereikt 120 FPS op middenklasse apparaten dankzij het eigen Recomposition systeem — een intelligent diff-algoritme dat alleen de gewijzigde widgets bijwerkt.
Belangrijkste punten
Jetpack Compose — is een declaratief framework van Google voor het bouwen van Android-gebruikersinterfaces, aangekondigd in 2019 en met een stabiele release in 2021. In tegenstelling tot het oude View System (XML + Activity/Fragment), gebruikt Compose geannoteerde Kotlin-functies — @Composable. De interface wordt volledig in Kotlin beschreven: er is geen scheiding tussen XML en code. Dit elimineerde een klasse fouten gerelateerd aan niet-overeenkomende id's in XML en Kotlin (type-safe synthetic hielp niet bij refactoring).
Compose is gebouwd op een eigen rendersysteem — Canvas, niet gebonden aan de View-hierarchie. Elke Composable tekent direct op Canvas, waarbij onMeasure/onDraw van View System wordt omzeild. Dit geeft een prestatieverbetering op complexe schermen: in Google-tests (2023) rendeerde een Compose-scherm met 200 elementen 40% sneller dan een analoog scherm op RecyclerView + ViewHolder.
Voor Compose is minSdk 21 (Android 5.0) en Kotlin 1.9+ vereist. Compose BOM (Bill of Materials) synchroniseert de versies van alle Compose-bibliotheken. Het framework is compatibel met bestaande code op View System: Compose wordt ingebed via ComposeView in XML, en oude Views via AndroidView in de Compose-hierarchie. Volgens Google Play Console (2025) dekt Android 5.0+ 97% van de actieve apparaten, dus compatibiliteit is geen beperking voor de meeste projecten.
@Composable — is een annotatie die een gewone Kotlin-functie omzet in een UI-bouwblok. Een Composable functie beschrijft hoe een interfacedeel — tekst, knop, lijst — eruit moet zien. In plaats van een waarde terug te geven, zendt de functie UI-componenten uit naar de compositie. Dit lijkt op een generator: elke functie voegt elementen toe aan het scherm bij aanroep.
@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
)
}
}
}
De functie ProfileCard ontvangt parameters (name, avatarUrl) en zendt Card → Row → AsyncImage + Text uit. Compositie — is een boom van uitgezonden componenten in een doorgang. Als parameters niet zijn gewijzigd, slaat Compose de functieaanroep over (recomposition skip). Als alleen name is gewijzigd, wordt alleen Text aangeroepen, de andere elementen worden niet hertekend. Zulke intelligent recomposition — is het belangrijkste prestatievoordeel van Compose ten opzichte van handmatige optimalisatie van View System.
Composable functies maken actief gebruik van slots — trailing lambda, content: @Composable (() -> Unit). Dit maakt het mogelijk om containers te maken: Card, Column, Row accepteren een content-lambda en de inhoud wordt ingebed op de slot-positie. Slot API verving XML-attributen zoals android:layout_gravity — nu wordt de positie van onderliggende elementen bepaald door Kotlin-code binnen het content-blok.
Status in Compose — is elke waarde die in de loop van de tijd kan veranderen. Wanneer de status verandert, plant Compose recomposition voor alle componenten die deze status lezen. Het mechanisme lijkt op React hooks: mutableStateOf retourneert MutableState, het lezen van .value abonneert de huidige compositie automatisch op wijzigingen.
@Composable
fun CounterExample() {
var count by remember { mutableStateOf(0) }
Column(modifier = Modifier.padding(16.dp)) {
Text("Ingedrukt: $count")
Button(onClick = { count++ }) {
Text("Vergroten")
}
}
}
@Composable
fun UserScreen(viewModel: UserViewModel) {
val userName by viewModel.userName.collectAsState()
Text("Gebruiker: $userName")
}
remember bewaart de waarde tussen recomposities — anders zou mutableStateOf opnieuw worden aangemaakt bij elke UI-update. collectAsState() converteert StateFlow van ViewModel naar een Compose-compatibele status. Aanbeveling — gebruik voor schermstatus ViewModel met StateFlow, voor lokale status (bijv. uitgevouwen kaart) — mutableStateOf. Deze scheiding volgt het principe van “Slimme/domme” componenten.
State Hoisting — is een patroon waarbij status van een kindcomponent naar een bovenliggende component wordt verplaatst. De ouder geeft de waarde en callback door via parameters, het kind roept de callback aan bij wijziging. De ouder slaat mutableStateOf op, het kind alleen de parameters. Dit maakt de component herbruikbaar en testbaar: dezelfde TextField kan met elke gegevensbron worden gebruikt.
Modifier — is een object dat transformaties van een Composable beschrijft: grootte, marges, achtergrond, klikverwerking, animatie, scrollen. Modifiers worden toegepast via een aanroepketen: Modifier.fillMaxWidth().padding(16.dp).background(Color.Blue).clickable { }. Elke aanroep retourneert een nieuwe Modifier met de toegevoegde eigenschap — zonder mutatie van het originele object.
De volgorde van modifiers is belangrijk. Modifier.padding(16.dp).background(Color.Blue) kleurt het gebied met marge. Modifier.background(Color.Blue).padding(16.dp) kleurt de binnenste rechthoek, terwijl de marge transparant blijft. Mechanica lijkt op het CSS-boxmodel: padding → background werkt als margin + background; background → padding — als background + padding binnenin. De ontwikkelaar hoeft alleen te onthouden: padding eerst = buitenmarge, padding daarna = binnenmarge.
Als ingebouwde modifiers niet volstaan, wordt een aangepaste modifier gemaakt via Modifier.composed { ... } of Modifier.then(). Binnen een aangepaste modifier kunnen lay-outmetingen (Modifier.layout { measurable, constraints -> ... }), tekenen (Modifier.drawWithContent { ... }), gebaren (Modifier.pointerInput { ... }) worden gebruikt. Voorbeeld: modifier voor een pulserende animatie bij indrukken — meet de grootte, start bij klik een schaalanimatie via animateFloatAsState.
Voor animaties biedt Compose animate*AsState (animateFloatAsState, animateColorAsState, animateDpAsState) — waarden animeren tussen oude en nieuwe status bij wijziging. Als animatie voor verschijnen/verdwijnen nodig is — AnimatedVisibility en AnimatedContent met ingebouwde overgangen (fade, slide, expand). Alle animaties werken op de graphics layer, zonder onnodige compositie te veroorzaken.
Composable functies mogen geen nevenacties direct uitvoeren (netwerkverzoeken, timers, abonnementen) — ze worden bij elke recomposition aangeroepen, wat zou leiden tot duplicatie van verzoeken. Voor neveneffecten biedt Compose de Effect-functiefamilie: LaunchedEffect start een coroutine bij binnenkomst in de compositie en annuleert bij verlaten, DisposableEffect — voor bronnen die expliciete opschoning vereisen (sensoren, 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("Waarde: $sensorValue")
}
@Composable
fun UserGreeting(userId: String) {
LaunchedEffect(userId) {
val profile = api.fetchProfile(userId)
// statusupdate
}
}
LaunchedEffect(userId) wordt herstart als userId is gewijzigd — de vorige coroutine wordt geannuleerd, een nieuwe start met de nieuwe userId. Dit elimineert handmatig beheer van het annuleren van verzoeken. DisposableEffect(Unit) — effect met vaste sleutel Unit, wordt geactiveerd bij binnenkomst in de compositie en roept onDispose aan bij verlaten. SensorReader registreert een luisteraar en schrijft zich uit bij het verlaten van het scherm — zonder risico op geheugenlekken.
Als een coroutine moet worden gestart niet bij binnenkomst in de compositie, maar bij een gebeurtenis (knopdruk), wordt rememberCoroutineScope() gebruikt. Het retourneert een CoroutineScope gebonden aan de levenscyclus van de Composable, zonder DisposableEffect. Voorbeeld: starten van een netwerkverzoek bij klik op een knop — scope.launch { viewModel.loadData() }.
De keuze tussen Compose en View System — de belangrijkste architectuurvraag voor een Android-ontwikkelaar in 2026. Beide technologieen worden ondersteund door Google, maar Compose is de belangrijkste richting waar Google middelen in investeert. View System krijgt alleen kritieke fixes en wordt niet verder ontwikkeld. Het verschil komt tot uiting in syntaxis, statusbeheer, prestaties en ontwikkelingstijd.
| Aspect | Jetpack Compose | View System |
|---|---|---|
| UI-beschrijving | Kotlin @Composable functies | XML + Activity/Fragment |
| Status | mutableStateOf, StateFlow, automatisch hertekenen | findViewById, handmatig: setText, notifyDataSetChanged |
| Prestaties | Intelligent recomposition, Canvas-rendering | View-hierarchie, measure/layout/draw |
| Animaties | animate*AsState, AnimatedVisibility, ingebouwd | ValueAnimator, ObjectAnimator, Transition |
| Compatibiliteit | minSdk 21, ComposeView/AndroidView bruggen | Alle versies |
| APK-grootte | +3–5 MB voor Compose | Zonder overhead |
Voor nieuwe projecten beveelt Google Jetpack Compose aan als standaard voor UI-ontwikkeling. View System blijft voor ondersteuning van code geschreven voor 2021 en gevallen waarin een minimale APK-grootte vereist is (bijv. voor opkomende markten met instapapparaten). Compose vermindert de hoeveelheid UI-code met 30–50% in vergelijking met View System dankzij declaratieve syntax en ingebouwde animaties.
Veelgestelde vragen
Ja, via ComposeView in XML. Voeg een dependency op Compose toe en omhul het scherm of een deel ervan in ComposeView { MyComposable() }. Migratie gaat scherm voor scherm.
Oorzaak — de status wordt te hoog gehesen of er worden veranderlijke objecten gebruikt. Oplossing: derivedStateOf voor afgeleide gegevens en remember voor stabiele verwijzingen.
Gebruik LazyColumn (analoog aan RecyclerView). Elementen worden aangemaakt en hergebruikt tijdens het scrollen. Voor complexe lijsten met verschillende celtypen — LazyColumn { items(items, key = { it.id }) { ... } }.
Nee, u kunt direct met Compose beginnen. Kennis van View System helpt bij het onderhouden van legacy-code, maar Compose is een zelfstandig ecosysteem met eigen documentatie en patronen.
Ja, Material 3 — is het standaard thema van Compose sinds 2023. Het wordt aangesloten via implementation(“androidx.compose.material3:material3”). Material 2 wordt als verouderd beschouwd.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook