Recomposition — vad är det, ombyggnad av UI vid tillståndsändring

Författare: IT Sectr Publicerad: 2026-06-27 Lästid: 7 min

Recomposition är en mekanism i Jetpack Compose som automatiskt bygger om delar av användargränssnittet vid dataändring, utan manuell uppdatering av View-element. När en tillståndsvariabel som en Composable-funktion är beroende av ändrar värde, startar Compose om endast den funktionen och lämnar resten av UI-trädet oberört. Enligt Google Android Developers, 2026 möjliggör korrekt förståelse av Recomposition en minskning av antalet onödiga omritningar med 40–60%.

Huvudpunkter

  • Recomposition — omstart av Composable-funktioner vid ändring av deras indata eller State
  • Skipping — hoppa över funktioner vars parametrar inte har ändrats (jämförelse via equals)
  • Stability avgör om Compose kan hoppa över en funktion — stabila typer jämförs korrekt
  • Smart Recomposition startar om endast den minimala uppsättningen funktioner, inte hela trädet
  • Rekomposition garanterar inte omritning — Layout och Drawing kan hoppa över fasen

Vad är Recomposition i Jetpack Compose

Recomposition är omkörning av Composable-funktioner som redan har deltagit i Composition, med nya värden av parametrar eller tillstånd. Huvudsyftet med rekomposition är att synkronisera UI-trädet med aktuella data utan att bygga om hela gränssnittet från början. Till skillnad från Composition som sker en gång, kan Recomposition startas hundratals gånger under en skärms livstid.

Recomposition fungerar enligt principen smart invalidation: Compose spårar vilka State-objekt varje Composable-funktion läser och markerar för omstart endast de vars beroenden har ändrats. Detta uppnås genom snapshot-systemet, som registrerar alla läsoperationer av State under körning, och Composer, som mapperar dessa beroenden till specifika funktioner.

Det är viktigt att förstå: rekomposition betyder inte omedelbar omritning av skärmen. Compose arbetar i tre faser: Composition (bygga UI-beskrivning), Layout (beräkna storlekar och positioner) och Drawing (rita på canvas). Om efter rekomposition storlekar och position av element inte har ändrats, kan Layout-fasen hoppas över. Om utseendet inte har ändrats — hoppas Drawing över. Denna trefasarkitektur säkerställer minimal kostnad för varje UI-uppdatering.

Utlösare för rekomposition: vad orsakar omstart av funktioner

Det finns tre huvudsakliga utlösare för rekomposition. Första — ändring av State-objektet som läses i kroppen av en Composable-funktion. När mutableStateOf eller derivedStateOf ändrar sitt värde, markeras alla funktioner som registrerade läsning av detta State i föregående komposition för omstart.

Andra utlösaren — ändring av parametrar för Composable-funktionen vid anrop från den överordnade funktionen. Om den överordnade funktionen har skickat ett nytt värde (t.ex. text eller nummer har ändrats), kommer den underordnade funktionen att startas om, även om den inte läser State inuti sig. Compose jämför nya och gamla parametervärden via equals, och om de är lika — kan funktionen hoppas över.

Tredje utlösaren — ändring av CompositionLocal via CompositionLocalProvider. Alla funktioner som läser CompositionLocal via .current startas om vid ändring av provider. Denna mekanism används av MaterialTheme: ändring av tema (ljust/mörkt) orsakar rekomposition av alla komponenter som läser MaterialTheme.colorScheme.

kotlin
@Composable
fun RecompositionDemo() {
    var counter by remember { mutableStateOf(0) }
    var text by remember { mutableStateOf("Hello") }

    Column {
        Text("Räknare: $counter")  // rekomposition när räknaren ändras
        Text("Meddelande: $text")    // rekomposition när texten ändras

        Button(onClick = { counter++ }) {
            Text("+1")
        }
        Button(onClick = { text = "Värld" }) {
            Text("Ändra text")
        }
    }
}

Att trycka på knappen +1 ändrar counter, vilket orsakar rekomposition endast av första Text-raden och själva Column. Andra Text-raden, som visar text, startas inte om. Sådan isolering — resultatet av snapshot-systemet: varje Composable-funktion vet bara om de State-objekt som den har läst.

Optimering av rekomposition: praktiska tekniker

Optimering av rekomposition börjar med korrekt val av datastrukturer. Använd oföränderliga samlingar (listOf, mapOf) istället för föränderliga (mutableListOf). Compose jämför parametrar via equals, och om samlingen har ändrats men equals returnerade true — kommer funktionen inte att startas om. För föränderliga samlingar, använd SnapshotStateList, som implementerar korrekt spårning av ändringar på elementnivå.

Andra tekniken — separera stabila delar av UI till separata Composable-funktioner. Om en del av skärmen inte är beroende av ofta föränderligt tillstånd, separera den till en separat funktion med parametrar. När rekomposition kommer, får den stabila funktionen samma parametrar, Compose jämför dem och hoppar över körning. Detta är mer fördelaktigt än att starta om denna del inom en stor funktion där en del av parametrarna har ändrats.

Tredje tekniken — nycklar i LazyColumn. Ange alltid key för item i LazyColumn, LazyGrid och andra lata containrar. Nyckeln tillåter Compose att identifiera element vid ändring av listan: tillägg, borttagning eller omordning. Utan nyckel startar Compose om alla element i listan vid varje ändring, vilket på stora listor ger märkbar prestandaförlust.

kotlin
// Optimerad struktur: stabila delar separat utskilda
@Composable
fun OptimizedScreen(items: List<Item>) {
    Column {
        Header()                         // beror inte på objekt — ingen rekomposition
        Spacer(modifier = Modifier.height(8.dp))
        LazyColumn {
            items(items, key = { it.id }) { item ->
                ItemRow(item = item)   // rekomposition endast för ändrade objekt
            }
        }
    }
}

@Composable
fun Header() {
    Text("Objektlista", style = MaterialTheme.typography.headlineMedium)
}

@Composable
fun ItemRow(item: Item) {
    Text(item.title)
}

Skipping och Stability i Compose

Skipping är en mekanism där Compose hoppar över körningen av en Composable-funktion om alla dess parametrar inte har ändrats. För att skipping ska fungera korrekt måste parametertyperna vara stabila (stable). Kotlin-kompilatorn markerar som stabila: primitiva typer (Int, Float, Boolean), String, lambda-funktioner, samt klasser vars alla fält är stabila och val.

Stability är en annotering @Stable eller @Immutable som kan läggas till anpassade dataklasser. Om en klass innehåller ett föränderligt fält (var), betraktar kompilatorn den som instabil och Compose kan inte hoppa över funktioner med sådana parametrar. För klasser med var, använd @Stable om du garanterar att meddelandet om ändring kommer att skickas via snapshot-systemet.

Stability kan kontrolleras via kompilatorflaggan -P "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=. /reports". Den genererar en rapport med en lista över alla Composable-funktioner och deras parametrar med stabilitetsindikation. Om en parameter är instabil — skipping för den funktionen är omöjlig och den kommer att startas om vid varje rekomposition av föräldern.

TypStabilitetSkipping
Int, Float, BooleanStabilJa
StringStabilJa
LambdaStabilJa
data class med val-fältStabilJa
data class med var-fältInstabilNej
List<String>InstabilNej

Observera: List<String> anses vara instabil eftersom det är ett gränssnitt, inte en konkret implementering. Använd immutableListOf() från Kotlin Collections Immutable-biblioteket eller linda in listan i en @Stable-klass. Lambda är alltid stabil, eftersom dess equals endast jämför referenser, och vid skapande av en ny lambda på anropsplatsen startas den överordnade funktionen också om.

Övervakning av rekompositioner i Android Studio

För övervakning av rekompositioner tillhandahåller Android Studio Layout Inspector med läget Compose Recomposition Counts. I detta läge visar varje Composable-funktion antalet rekompositioner och orsaker till omstart. Detta gör det möjligt att snabbt hitta funktioner som rekomponeras för ofta och bestämma grundorsaken — instabila parametrar eller onödiga State-beroenden.

Ytterligare verktyg: Compose Metrics (insamling av statistik via instrumentation-tester) och Recomposition Timer (mätning av körningstid för varje funktion). Google rekommenderar att aktivera dessa verktyg i profileringsfasen och inaktivera i release-versioner, eftersom de lägger till upp till 20% overhead på varje rekomposition.

Vid analys av rekompositioner, leta efter mönster av unnecessary recomposition: en funktion startas om trots att dess utdata-UI inte borde ändras. En vanlig orsak är användning av lambda utan remember, där varje gång ett nytt lambda-objekt skapas och Compose anser parametern ändrad. Lösning: linda in lambdas i remember { } med fasta infångningar.

kotlin
// Dåligt: ny lambda vid varje föräldrarekomposition
@Composable
fun Parent() {
    Child(onClick = { doSomething() })  // ny lambda varje gång
}

// Bra: remember stabiliserar lambdan
@Composable
fun Parent() {
    val onClick = remember { { doSomething() } }
    Child(onClick = onClick)  // samma referens
}

Vanliga frågor

Betyder rekomposition omritning av skärmen?

Nej, rekomposition är bara Composition-fasen. Efter den utförs Layout och Drawing. Om efter rekomposition storlekar och position av element inte har ändrats, kan Layout och Drawing helt hoppas över, vilket sparar GPU-resurser.

Hur ofta kan rekomposition ske?

Vid animationer kan rekomposition startas upp till 120 gånger per sekund (120fps). För normal interaktion — 10–60 gånger per sekund. Det är viktigt att varje rekomposition ryms inom bildbudgeten (8–16 ms), annars kommer applikationen att sakta ner.

Varför rekomponeras en funktion trots att State inte har ändrats?

Orsaken — ändring av parameter från den överordnade funktionen. Föräldern startas om (av egen anledning) och skickar ett nytt värde. För att undvika detta, kontrollera stability av parametrar och använd remember för stabilisering av lambdas och beräknade värden.

Kan rekomposition inaktiveras för en specifik funktion?

Direkt inaktivering finns inte, men det finns påtvingad skipping via readInComposition — State läses utanför funktionskroppen, vilket inte registrerar beroende. Använd detta försiktigt: funktionen kommer inte att reagera på ändringar, vilket kan leda till föråldrad UI.

Vilket är dyrare: Composition eller Recomposition?

Composition är dyrare eftersom det skapar alla platser och trädnoder från början. Recomposition återanvänder befintliga platser och uppdaterar endast deras värden. I praktiken tar Composition av en skärm 2–10 ms och rekomposition av ett element — 0.1–1 ms.

Sammanfattning

  • Recomposition — selektiv omstart av Composable-funktioner vid ändring av deras State eller parametrar
  • Snapshot system spårar funktioners beroenden av State och planerar rekomposition
  • Skipping är endast möjligt för funktioner med stabila parametrar (@Stable eller immutble)
  • Tre utlösare för rekomposition: ändring av State, ändring av parametrar, ändring av CompositionLocal
  • List<T> anses instabil — använd oföränderliga samlingar för korrekt skipping
  • Layout Inspector visar rekompositionsräknare för varje funktion
  • Rekommendation: separera stabila delar av UI till separata funktioner och använd remember för lambdas

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också