Recomposition ay isang mekanismo ng Jetpack Compose na awtomatikong nagtatayo muli ng mga bahagi ng user interface kapag nagbago ang data, nang walang manu-manong pag-update ng mga elemento ng View. Kapag ang variable ng estado na nakadepende ng Composable function ay nagbago ng halaga, Compose ay nag-restart lamang ng function na iyon, iniiwan ang natitirang bahagi ng UI tree na hindi nagalaw. Ayon sa Google Android Developers, 2026, ang tamang pag-unawa sa Recomposition ay nagpapahintulot na bawasan ang bilang ng mga hindi kinakailangang pag-redraw ng 40–60%.
Mga pangunahing punto
Recomposition ay ang muling pagpapatakbo ng Composable function na lumahok na sa Composition, na may mga bagong halaga ng parameter o estado. Ang pangunahing layunin ng rekomposisyon ay i-synchronize ang UI tree sa kasalukuyang data nang hindi itinatayo muli ang buong interface mula sa simula. Hindi tulad ng Composition na nangyayari nang isang beses, ang Recomposition ay maaaring magsimula ng daan-daang beses sa habang-buhay ng isang screen.
Ang Recomposition ay gumagana sa prinsipyo ng smart invalidation: Sinusubaybayan ng Compose kung aling mga State object ang binabasa ng bawat Composable function at minamarkahan para sa restart lamang ang mga nagbago ang dependencies. Ito ay nakakamit sa pamamagitan ng snapshot system, na nagtatala ng lahat ng operasyon ng pagbasa ng State sa panahon ng execution, at Composer, na nagmamapa ng mga dependency na ito sa mga tiyak na function.
Mahalagang maunawaan: ang rekomposisyon ay hindi nangangahulugan ng agarang pag-redraw ng screen. Ang Compose ay gumagana sa tatlong phase: Composition (pagbuo ng UI description), Layout (pagkalkula ng mga sukat at posisyon) at Drawing (pagguhit sa canvas). Kung pagkatapos ng rekomposisyon ang mga sukat at posisyon ng mga elemento ay hindi nagbago, ang Layout phase ay maaaring laktawan. Kung ang hitsura ay hindi nagbago — Drawing ay laktawan. Ang three-phase architecture na ito ay nagsisiguro ng minimal na gastos ng bawat pag-update ng UI.
Mayroong tatlong pangunahing trigger ng rekomposisyon. Una — pagbabago ng State object na binasa sa katawan ng Composable function. Kapag ang mutableStateOf o derivedStateOf ay nagbago ng halaga, lahat ng function na nagtala ng pagbasa ng State na ito sa nakaraang komposisyon ay minamarkahan para sa restart.
Pangalawang trigger — pagbabago ng mga parameter ng Composable function kapag tinawag mula sa parent function. Kung ang parent function ay nagpasa ng bagong halaga (hal. nagbago ang text o numero), ang child function ay irerestart, kahit na hindi ito nagbabasa ng State sa loob. Inihahambing ng Compose ang bago at lumang halaga ng parameter sa pamamagitan ng equals, at kung pantay — ang function ay maaaring laktawan.
Pangatlong trigger — pagbabago ng CompositionLocal sa pamamagitan ng CompositionLocalProvider. Lahat ng function na nagbabasa ng CompositionLocal sa pamamagitan ng .current ay irerestart kapag nagbago ang provider. Ang mekanismong ito ay ginagamit ng MaterialTheme: ang pagbabago ng tema (maliwanag/dilim) ay nagdudulot ng rekomposisyon ng lahat ng component na nagbabasa ng MaterialTheme.colorScheme.
@Composable
fun RecompositionDemo() {
var counter by remember { mutableStateOf(0) }
var text by remember { mutableStateOf("Hello") }
Column {
Text("Counter: $counter") // rekomposisyon kapag nagbago ang counter
Text("Mensahe: $text") // rekomposisyon kapag nagbago ang text
Button(onClick = { counter++ }) {
Text("+1")
}
Button(onClick = { text = "Mundo" }) {
Text("Baguhin ang text")
}
}
}
Ang pagpindot sa button na +1 ay nagbabago ng counter, na nagdudulot ng rekomposisyon lamang ng unang linya ng Text at ng Column mismo. Ang pangalawang linya ng Text, na nagpapakita ng text, ay hindi irerestart. Ang ganitong paghihiwalay — resulta ng snapshot system: bawat Composable function ay alam lamang ang tungkol sa mga State object na binasa nito.
Ang pag-optimize ng rekomposisyon ay nagsisimula sa tamang pagpili ng mga istruktura ng data. Gumamit ng hindi nagbabagong koleksyon (listOf, mapOf) sa halip ng nagbabago (mutableListOf). Inihahambing ng Compose ang mga parameter sa pamamagitan ng equals, at kung nagbago ang koleksyon ngunit nagbalik ng true ang equals — ang function ay hindi irerestart. Para sa nagbabagong koleksyon, gamitin ang SnapshotStateList, na nagpapatupad ng tamang pagsubaybay ng pagbabago sa antas ng elemento.
Pangalawang teknik — paghihiwalay ng mga stable na bahagi ng UI sa hiwalay na Composable function. Kung ang isang bahagi ng screen ay hindi nakadepende sa madalas na nagbabagong estado, ihiwalay ito sa isang hiwalay na function na may mga parameter. Kapag dumating ang rekomposisyon, ang stable na function ay tumatanggap ng parehong parameter, inihahambing sila ng Compose at nilalaktawan ang execution. Ito ay mas kapaki-pakinabang kaysa i-restart ang bahaging ito sa loob ng isang malaking function kung saan ang ilang parameter ay nagbago.
Pangatlong teknik — mga key sa LazyColumn. Palaging magbigay ng key para sa item sa LazyColumn, LazyGrid, at iba pang tamad na lalagyan. Ang key ay nagpapahintulot sa Compose na kilalanin ang mga elemento kapag nagbago ang listahan: pagdaragdag, pagtanggal, o pag-aayos muli. Kung walang key, irerestart ng Compose ang lahat ng elemento ng listahan sa bawat pagbabago, na sa malalaking listahan ay nagbibigay ng kapansin-pansing pagbaba ng pagganap.
// Optimized na istraktura: stable na bahagi na hiwalay
@Composable
fun OptimizedScreen(items: List<Item>) {
Column {
Header() // hindi nakadepende sa mga item — walang rekomposisyon
Spacer(modifier = Modifier.height(8.dp))
LazyColumn {
items(items, key = { it.id }) { item ->
ItemRow(item = item) // rekomposisyon para lamang sa mga nagbagong item
}
}
}
}
@Composable
fun Header() {
Text("Listahan ng item", style = MaterialTheme.typography.headlineMedium)
}
@Composable
fun ItemRow(item: Item) {
Text(item.title)
}
Skipping ay isang mekanismo kung saan nilalaktawan ng Compose ang execution ng Composable function kung ang lahat ng parameter nito ay hindi nagbago. Para gumana nang tama ang skipping, ang mga uri ng parameter ay dapat na stable. Ang Kotlin compiler ay nagmamarka bilang stable: mga primitive na uri (Int, Float, Boolean), String, lambda function, pati na rin ang mga klase na ang lahat ng field ay stable at val.
Stability ay isang annotation na @Stable o @Immutable na maaaring idagdag sa mga custom na data class. Kung ang isang klase ay naglalaman ng nagbabagong field (var), itinuturing ito ng compiler na hindi stable at hindi maaaring laktawan ng Compose ang mga function na may ganitong mga parameter. Para sa mga klase na may var, gamitin ang @Stable kung ginagarantiya mo na ang abiso tungkol sa pagbabago ay ipapadala sa pamamagitan ng snapshot system.
Ang stability ay maaaring suriin sa pamamagitan ng compiler flag -P "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=. /reports". Ito ay bumubuo ng ulat na may listahan ng lahat ng Composable function at kanilang mga parameter na may indikasyon ng stability. Kung ang isang parameter ay hindi stable — ang skipping para sa function na iyon ay imposible at ito ay irerestart sa bawat rekomposisyon ng parent.
| Uri | Stability | Skipping |
|---|---|---|
| Int, Float, Boolean | Stable | Oo |
| String | Stable | Oo |
| Lambda | Stable | Oo |
| data class na may val field | Stable | Oo |
| data class na may var field | Hindi stable | Hindi |
| List<String> | Hindi stable | Hindi |
Pansinin: List<String> ay itinuturing na hindi stable dahil ito ay isang interface, hindi isang konkretong implementasyon. Gumamit ng immutableListOf() mula sa Kotlin Collections Immutable library o balutin ang listahan sa isang @Stable na klase. Ang Lambda ay palaging stable, dahil ang equals nito ay naghahambing lamang ng mga reference, at sa paglikha ng bagong lambda sa lugar ng tawag, ang parent function ay irerestart din.
Para sa pag-monitor ng mga rekomposisyon, ang Android Studio ay nagbibigay ng Layout Inspector na may mode na Compose Recomposition Counts. Sa mode na ito, ang bawat Composable function ay nagpapakita ng bilang ng mga rekomposisyon at mga dahilan ng restart. Ito ay nagpapahintulot na mabilis na mahanap ang mga function na masyadong madalas na rekomposisyon at matukoy ang ugat na sanhi — hindi stable na parameter o hindi kinakailangang State dependencies.
Mga karagdagang tool: Compose Metrics (pagkolekta ng statistics sa pamamagitan ng instrumentation tests) at Recomposition Timer (pagsukat ng oras ng execution ng bawat function). Inirerekomenda ng Google na i-on ang mga tool na ito sa yugto ng profiling at i-off sa mga release build, dahil nagdaragdag sila ng overhead hanggang 20% sa bawat rekomposisyon.
Sa pagsusuri ng mga rekomposisyon, hanapin ang mga pattern ng unnecessary recomposition: ang function ay irerestart kahit na ang output UI nito ay hindi dapat magbago. Ang karaniwang dahilan ay ang paggamit ng lambda nang walang remember, kapag bawat oras ay lumilikha ng bagong lambda object at itinuturing ng Compose na nagbago ang parameter. Solusyon: balutin ang lambda sa remember { } na may mga fixed capture.
// Masama: bagong lambda sa bawat rekomposisyon ng parent
@Composable
fun Parent() {
Child(onClick = { doSomething() }) // bagong lambda bawat pagkakataon
}
// Mabuti: remember ay nagpapatatag ng lambda
@Composable
fun Parent() {
val onClick = remember { { doSomething() } }
Child(onClick = onClick) // parehong reference
}
Mga madalas itanong
Hindi, ang rekomposisyon ay lamang ang Composition phase. Pagkatapos nito ay isinasagawa ang Layout at Drawing. Kung pagkatapos ng rekomposisyon ang mga sukat at posisyon ng mga elemento ay hindi nagbago, ang Layout at Drawing ay maaaring ganap na laktawan, na nakakatipid ng mga mapagkukunan ng GPU.
Sa mga animation, ang rekomposisyon ay maaaring magsimula ng hanggang 120 beses bawat segundo (120fps). Para sa ordinaryong interaksyon — 10–60 beses bawat segundo. Mahalaga na ang bawat rekomposisyon ay nasa loob ng budget ng frame (8–16 ms), kung hindi ay babagal ang application.
Ang dahilan — pagbabago ng parameter mula sa parent function. Ang parent ay irerestart (para sa sarili nitong dahilan) at nagpapasa ng bagong halaga. Upang maiwasan ito, suriin ang stability ng mga parameter at gamitin ang remember para sa pag-stabilize ng lambda at mga kinakalkulang halaga.
Walang direktang pag-off, ngunit mayroong force skipping sa pamamagitan ng readInComposition — ang State ay binabasa sa labas ng katawan ng function, na hindi nagtatala ng dependency. Gamitin ito nang maingat: ang function ay hindi tutugon sa mga pagbabago, na maaaring humantong sa lumang UI.
Composition ay mas mahal dahil lumilikha ito ng lahat ng slot at node ng tree mula sa simula. Ang Recomposition ay gumagamit muli ng mga umiiral na slot at ina-update lamang ang kanilang mga halaga. Sa praktika, ang Composition ng isang screen ay tumatagal ng 2–10 ms, at ang rekomposisyon ng isang elemento — 0.1–1 ms.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din