Recomposition — mi ez, a felhasználói felület újraépítése állapotváltozás esetén

Szerző: IT Sectr Megjelenés: 2026-06-27 Olvasási idő: 7 perc

Recomposition a Jetpack Compose mechanizmusa, amely automatikusan átépíti a felhasználói felület részeit adatváltozás esetén, a View elemek manuális frissítése nélkül. Amikor egy állapotváltozó, amelytől egy Composable függvény függ, megváltoztatja az értékét, a Compose csak azt a függvényt indítja újra, a UI-fa többi részét érintetlenül hagyva. A Google Android Developers, 2026 adatai szerint a Recomposition helyes megértése lehetővé teszi a felesleges újrarajzolások számának 40–60%-os csökkentését.

Főbb pontok

  • Recomposition — Composable függvények újraindítása a bemeneti adatok vagy State megváltozásakor
  • Skipping — azon függvények kihagyása, amelyek paraméterei nem változtak (equals összehasonlítás)
  • Stability meghatározza, hogy a Compose kihagyhat-e egy függvényt — a stabil típusok helyesen összehasonlíthatók
  • Smart Recomposition csak a minimális függvénykészletet indítja újra, nem a teljes fát
  • Újrakomponálás nem garantál újrarajzolást — Layout és Drawing kihagyhatja a fázist

Mi az a Recomposition a Jetpack Compose-ban

Recomposition a már Composition-ban részt vett Composable függvények újravégrehajtása a paraméterek vagy állapot új értékeivel. Az újrakomponálás fő célja a UI-fa szinkronizálása az aktuális adatokkal anélkül, hogy a teljes felületet a nulláról építené újra. Az egyszeri Composition-tól eltérően a Recomposition több százszor is elindulhat egy képernyő élettartama során.

A Recomposition a smart invalidation elve alapján működik: a Compose nyomon követi, hogy mely State objektumokat olvassa az egyes Composable függvények, és csak azokat jelöli meg újraindításra, amelyek függőségei megváltoztak. Ezt a snapshot-rendszer teszi lehetővé, amely rögzíti az összes State-olvasási műveletet a végrehajtás során, és a Composer, amely ezeket a függőségeket konkrét függvényekhez rendeli.

Fontos megérteni: az újrakomponálás nem jelenti a képernyő azonnali újrarajzolását. A Compose három fázisban működik: Composition (a UI leírás felépítése), Layout (méretek és pozíciók kiszámítása) és Drawing (rajzolás a vászonra). Ha az újrakomponálás után az elemek méretei és pozíciói nem változtak, a Layout fázis kihagyható. Ha a megjelenés nem változott — a Drawing kimarad. Ez a háromfázisú architektúra biztosítja az egyes UI-frissítések minimális költségét.

Az újrakomponálás triggerei: mi okozza a függvények újraindítását

Az újrakomponálásnak három fő triggere van. Az első — a Composable függvény törzsében olvasott State objektum megváltozása. Amikor a mutableStateOf vagy derivedStateOf megváltoztatja az értékét, az összes függvény, amely regisztrálta ennek a State-nek az olvasását az előző kompozícióban, újraindításra kerül megjelölésre.

A második trigger — a paraméterek megváltozása a Composable függvény szülő függvényből történő meghívásakor. Ha a szülő függvény új értéket adott át (pl. a szöveg vagy szám megváltozott), a gyermek függvény újraindul, még akkor is, ha nem olvas State-et magában. A Compose összehasonlítja a paraméterek új és régi értékeit equals segítségével, és ha egyenlők — a függvény kihagyható.

A harmadik trigger — a CompositionLocal megváltozása a CompositionLocalProvider segítségével. Az összes függvény, amely .current-en keresztül olvassa a CompositionLocal-t, újraindul a provider változásakor. Ezt a mechanizmust használja a MaterialTheme: a téma váltása (világos/sötét) az összes olyan komponens újrakomponálását okozza, amely olvassa a MaterialTheme.colorScheme-t.

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

    Column {
        Text("Számláló: $counter")  // újrakomponálás a számláló változásakor
        Text("Üzenet: $text")    // újrakomponálás a szöveg változásakor

        Button(onClick = { counter++ }) {
            Text("+1")
        }
        Button(onClick = { text = "Világ" }) {
            Text("Szöveg módosítása")
        }
    }
}

A +1 gomb megnyomása megváltoztatja a counter-t, ami csak az első Text sor és maga a Column újrakomponálását okozza. A második Text sor, amely a text-et jeleníti meg, nem indul újra. Az ilyen elkülönítés a snapshot-rendszer eredménye: minden Composable függvény csak azokról a State objektumokról tud, amelyeket elolvasott.

Az újrakomponálás optimalizálása: gyakorlati technikák

Az újrakomponálás optimalizálása az adatstruktúrák helyes megválasztásával kezdődik. Használjon megváltoztathatatlan gyűjteményeket (listOf, mapOf) a változtathatók (mutableListOf) helyett. A Compose equals segítségével hasonlítja össze a paramétereket, és ha a gyűjtemény megváltozott, de az equals true-t adott vissza — a függvény nem indul újra. Változtatható gyűjteményekhez használja a SnapshotStateList-et, amely helyesen követi a változásokat elemszinten.

A második technika — a stabil részek kiemelése a UI-ból külön Composable függvényekbe. Ha a képernyő egy része nem függ a gyakran változó állapottól, emelje ki egy külön függvénybe paraméterekkel. Amikor újrakomponálás történik, a stabil függvény ugyanazokat a paramétereket kapja, a Compose összehasonlítja őket és kihagyja a végrehajtást. Ez előnyösebb, mint ezt a részt egy nagy függvény részeként újraindítani, ahol a paraméterek egy része megváltozott.

A harmadik technika — kulcsok a LazyColumn-ban. Mindig adjon meg key-t az item-hez a LazyColumn, LazyGrid és más lusta tárolókban. A kulcs lehetővé teszi a Compose számára az elemek azonosítását a lista változásakor: hozzáadás, törlés vagy átrendezés. Kulcs nélkül a Compose a lista összes elemét újraindítja minden változásnál, ami nagy listáknál észrevehető teljesítménycsökkenést okoz.

kotlin
// Optimalizált struktúra: stabil részek külön kiemelve
@Composable
fun OptimizedScreen(items: List<Item>) {
    Column {
        Header()                         // nem függ az elemektől — nincs újrakomponálás
        Spacer(modifier = Modifier.height(8.dp))
        LazyColumn {
            items(items, key = { it.id }) { item ->
                ItemRow(item = item)   // újrakomponálás csak a megváltozott elemekhez
            }
        }
    }
}

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

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

Skipping és Stability a Compose-ban

Skipping egy mechanizmus, amelyben a Compose kihagyja egy Composable függvény végrehajtását, ha az összes paramétere nem változott. A skipping helyes működéséhez a paramétertípusoknak stabilnak (stable) kell lenniük. A Kotlin fordító stabilként jelöli meg: a primitív típusokat (Int, Float, Boolean), String-et, lambda függvényeket, valamint azokat az osztályokat, amelyeknek minden mezője stabil és val.

Stability egy @Stable vagy @Immutable annotáció, amely egyéni adatosztályokhoz adható hozzá. Ha egy osztály változtatható mezőt (var) tartalmaz, a fordító instabilnak tekinti, és a Compose nem tudja kihagyni az ilyen paraméterekkel rendelkező függvényeket. A var-osztályokhoz használja a @Stable-t, ha garantálja, hogy a változásról szóló értesítés a snapshot-rendszeren keresztül kerül elküldésre.

A Stability a fordítói flag segítségével ellenőrizhető: -P "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=. /reports". Ez egy jelentést generál az összes Composable függvény és paramétereik listájával, stability jelzéssel. Ha egy paraméter instabil — a skipping lehetetlen, és a függvény minden szülő újrakomponálásakor újraindul.

TípusStabilitásSkipping
Int, Float, BooleanStabilIgen
StringStabilIgen
LambdaStabilIgen
data class val mezőkkelStabilIgen
data class var mezőkkelInstabilNem
List<String>InstabilNem

Figyelje meg: a List<String> instabilnak számít, mert ez egy interfész, nem konkrét implementáció. Használja az immutableListOf()-ot a Kotlin Collections Immutable könyvtárból, vagy csomagolja a listát egy @Stable osztályba. A Lambda mindig stabil, mivel az equals csak referenciákat hasonlít össze, és egy új lambda létrehozásakor a hívás helyén a szülő függvény is újraindul.

Újrakomponálások figyelése az Android Studio-ban

Az újrakomponálások figyeléséhez az Android Studio Layout Inspector-t biztosít Compose Recomposition Counts móddal. Ebben a módban minden Composable függvény megjeleníti az újrakomponálások számát és az újraindítás okait. Ez lehetővé teszi a túl gyakran újrakomponált függvények gyors megtalálását és a kiváltó ok meghatározását — instabil paraméterek vagy felesleges State-függőségek.

További eszközök: Compose Metrics (statisztikák gyűjtése instrumentation teszteken keresztül) és Recomposition Timer (az egyes függvények végrehajtási idejének mérése). A Google azt javasolja, hogy ezeket az eszközöket a profilozási fázisban kapcsolja be, és a kiadás build-ekben kapcsolja ki, mivel akár 20% többletterhelést is adnak minden újrakomponáláshoz.

Az újrakomponálások elemzésekor keresse az unnecessary recomposition mintákat: a függvény újraindul, holott a kimeneti UI-nak nem kellene változnia. Gyakori ok a lambda remember nélküli használata, amikor minden alkalommal új lambda objektum jön létre, és a Compose a paramétert megváltozottnak tekinti. Megoldás: a lambdák becsomagolása remember { }-be fix capture-ökkel.

kotlin
// Rossz: új lambda minden szülő újrakomponáláskor
@Composable
fun Parent() {
    Child(onClick = { doSomething() })  // minden alkalommal új lambda
}

// Jó: a remember stabilizálja a lambdát
@Composable
fun Parent() {
    val onClick = remember { { doSomething() } }
    Child(onClick = onClick)  // ugyanaz a referencia
}

Gyakran ismételt kérdések

Az újrakomponálás a képernyő újrarajzolását jelenti?

Nem, az újrakomponálás csak a Composition fázis. Ezt követi a Layout és a Drawing. Ha az újrakomponálás után az elemek méretei és pozíciói nem változtak, a Layout és Drawing teljesen kihagyható, ami GPU-erőforrásokat takarít meg.

Milyen gyakran történhet újrakomponálás?

Animációknál az újrakomponálás akár 120-szor is elindulhat másodpercenként (120fps). Normál interakció esetén — 10–60-szor másodpercenként. Fontos, hogy minden újrakomponálás beleférjen a képkocka keretébe (8–16 ms), különben az alkalmazás lassulni fog.

Miért újrakomponálódik egy függvény, ha a State nem változott?

Az ok — a paraméter megváltozása a szülő függvénytől. A szülő újraindul (saját okból) és új értéket ad át. Ennek elkerüléséhez ellenőrizze a paraméterek stability-jét és használja a remember-t a lambdák és számított értékek stabilizálásához.

Kikapcsolható az újrakomponálás egy adott függvényhez?

Közvetlen kikapcsolás nincs, de létezik kényszerített skipping a readInComposition segítségével — a State a függvény törzsén kívül kerül olvasásra, ami nem regisztrál függőséget. Használja ezt óvatosan: a függvény nem fog reagálni a változásokra, ami elavult UI-hoz vezethet.

Melyik drágább: Composition vagy Recomposition?

A Composition drágább, mert az összes slotot és fa-csomópontot a nulláról hozza létre. A Recomposition újrahasznosítja a meglévő slotokat, és csak azok értékeit frissíti. A gyakorlatban egy képernyő Composition-ja 2–10 ms-ot vesz igénybe, egy elem újrakomponálása pedig 0.1–1 ms-ot.

Összefoglalás

  • Recomposition — a Composable függvények szelektív újraindítása State vagy paramétereik változásakor
  • Snapshot system nyomon követi a függvények State-től való függőségeit és tervezi az újrakomponálást
  • Skipping csak stabil paraméterekkel rendelkező függvényeknél lehetséges (@Stable vagy immutable)
  • Három trigger az újrakomponáláshoz: State változása, paraméterek változása, CompositionLocal változása
  • List<T> instabilnak számít — használjon megváltoztathatatlan gyűjteményeket a helyes skipping-hez
  • Layout Inspector mutatja az újrakomponálási számlálókat minden függvényhez
  • Javaslat: emelje ki a UI stabil részeit külön függvényekbe, és használjon remember-t a lambdákhoz

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is