Composition — ay ang sentral na proseso sa Jetpack Compose, kung saan mula sa mga deskriptibong Composable function ay binuo ang isang buhay na UI tree na ipinapakita sa screen. Hindi tulad ng View system sa Android, kung saan ang layout ay nilo-load mula sa XML at ginagawang hindi nababagong mga bagay, ang Composition ay gumagana bilang isang dynamic na sistema: ang mga function ay isinasagawa, lumikha ng mga slot sa memorya, bumubuo ng hierarchy ng mga node at iniuugnay ito sa estado. Ayon sa Google Android Developers, 2026, ang pag-unawa sa Composition ay kritikal para sa pag-optimize ng performance ng Compose application.
Mga pangunahing punto
Composition — ay ang proseso ng pagpapatupad ng Composable function, na nagreresulta sa panloob na representasyon ng user interface sa anyo ng isang tree ng mga node. Ang bawat node ng tree na ito ay tumutugma sa alinman sa isang built-in na component (Text, Button, Image) o isang tawag sa isang custom na Composable function. Ang Composition ay hindi direktang lumilikha ng Android View objects — ito ay bumubuo ng abstract na paglalarawan na pagkatapos ay pinoproseso ng Layout at Drawing phases.
Ang pangunahing katangian ng Composition ay ang restartability nito. Ang bawat Composable function sa komposisyon ay maaaring i-restart anumang oras kung ang mga input parameter nito o ang mga state object na binasa nito ay nagbago. Hindi ni-restart ng system ang buong tree — tanging ang mga function na talagang umaasa sa binagong data.
Sa teknikal, ang Composition ay pinamamahalaan sa pamamagitan ng Composer — isang panloob na engine na ini-embed ng Kotlin compiler sa bawat Composable function. Ang Composer ay nagsusulat sa mga slot (mga grupo ng posisyon) ng impormasyon tungkol sa kung aling mga function ang tinawag, sa anong mga parameter, at sa anong pagkakasunud-sunod. Sa mga susunod na tawag, inihahambing ng Composer ang bagong data sa naka-save at nagpapasya tungkol sa pag-restart.
Ang proseso ng pagbuo ng UI tree ay nagsisimula sa pagtawag sa paraang setContent sa loob ng Activity o Fragment. Ang paraang ito ay lumilikha ng paunang Composition at naglulunsad ng pagpapatupad ng root Composable function. Pagkatapos, ang bawat nested Composable function ay nagdaragdag ng mga node nito sa tree, na bumubuo ng hierarchy: Row ay naglalaman ng Text at Button, Column ay naglalaman ng Image at Card, at iba pa.
Ang bawat node ng tree ay nakakakuha ng isang natatanging key ng posisyon, batay sa posisyon nito sa source code. Ang key na ito ay ginagamit para sa pagkilala ng node sa mga paulit-ulit na pagpapatupad. Ang key ng posisyon ay ang dahilan kung bakit ang pagkakasunud-sunod ng pagtawag ng Composable function ay hindi dapat umasa sa mga kondisyon: kung sa isang pagpapatupad ay tinawag ang A -> B, at sa susunod ay B -> A, hindi magagawa ng Compose na itugma ang luma at bagong mga node.
@Composable
fun AppScreen() {
Column { // Column node (posisyon 1)
HeaderSection() // HeaderSection node (posisyon 2)
ContentSection() // ContentSection node (posisyon 3)
FooterSection() // FooterSection node (posisyon 4)
}
}
@Composable
fun HeaderSection() {
Row { // Row node (posisyon 2.1)
Text("Pamagat") // Text node (posisyon 2.2)
Icon(...) // Icon node (posisyon 2.3)
}
}
Sa halimbawang ito, ang bawat tawag ay nakakakuha ng posisyon batay sa pagkakasunud-sunod sa code. Column (posisyon 1) ay naglalaman ng tatlong child node (posisyon 2, 3, 4). Ang HeaderSection ay nagdaragdag ng dalawa pang child node (2.1, 2.2, 2.3). Kung sa susunod na recomposition ang ContentSection ay tinawag bago ang HeaderSection, hindi magagawa ng Composer na itugma nang tama ang mga node — kaya ang patakaran: ang pagkakasunud-sunod ng pagtawag ng Composable function ay dapat na matatag.
Ang estado sa Composition ay pinamamahalaan sa pamamagitan ng mga bagay na uri ng State<T>. Kapag ang isang Composable function ay nagbabasa ng halaga mula sa State sa pamamagitan ng delegadong property (by), nagrerehistro ito ng dependency sa State na iyon. Kapag nagbago ang halaga, ang lahat ng function na nagbasa ng State na ito ay minarkahan para sa pag-restart sa susunod na yugto ng komposisyon.
Ang mekanismo ng pagrerehistro ng mga dependency ay tinatawag na snapshot system. Sa bawat oras na nagbago ang State, ang snapshot ay nagtatala ng lahat ng pagbabago at nag-abiso sa Composer kung aling mga function ang nakadepende sa State na ito. Mahalagang maunawaan: ang pagbabasa ng State sa non-Composable na code (hal. sa onClick lambda) ay hindi nagrerehistro ng dependency — tanging ang pagbabasa sa loob ng Composable function o sa mga lambda na isinagawa sa konteksto ng komposisyon.
Ang snapshot system ay gumagana nang transaksyonal: maraming pagbabago ng State sa loob ng isang kaganapan ay pinagsama sa isang transaksyon, na pumipigil sa maraming recomposition. Ito ay lalong mahalaga sa pagproseso ng mga kilos: sa isang paggalaw, maraming State object ang nagbabago, ngunit ang Compose ay nagsasagawa lamang ng isang recomposition.
@Composable
fun StateExample() {
var text by remember { mutableStateOf("Hello") }
var isVisible by remember { mutableStateOf(true) }
Column {
Text(text) // nagrerehistro ng dependency sa text
if (isVisible) { // nagrerehistro ng dependency sa isVisible
TextField(value = text, onValueChange = { text = it })
}
Button(onClick = { isVisible = !isVisible }) {
Text(if (isVisible) "Itago" else "Ipakita")
}
}
}
Ang pagbabago ng text ay humahantong sa recomposition lamang ng Column, Text at TextField. Ang Button at ang kondisyong isVisible ay nananatiling hindi nagbabago. Ang ganitong pagkakahiwalay ng recomposition ay isang pangunahing bentahe ng Compose kumpara sa mga system na nagre-redraw ng buong screen. Bawat Composable function ay sumusubaybay lamang sa mga State object na direktang binabasa nito.
Composition (komposisyon) at Recomposition (rekomposisyon) — ay dalawang magkaibang mode ng pagpapatupad ng Composable function. Ang Composition ay nangyayari nang isang beses sa paggawa ng screen: isinasagawa ng system ang lahat ng Composable function na may paunang halaga at binuo ang paunang UI tree. Ang Recomposition ay nangyayari nang maraming beses sa pagbabago ng data: ni-restart ng system ang mga function lamang na nakadepende sa binagong estado.
Ang mode na Composition ay nag-activate ng lahat ng node ng tree, naglalaan ng mga slot para sa bawat function, nagrerehistro ng lahat ng descendant. Ang Recomposition ay gumagana nang pili: inihahambing ng Compose ang mga bago at lumang halaga ng parameter ng bawat function, at kung hindi nagbago — ang function ay hindi isinasagawa (skipping).
Ang Composition at Recomposition ay nagkakaiba sa gastos. Ang unang Composition ay mas mahal, dahil nangangailangan ito ng kumpletong pagbuo ng tree at paglalaan ng mga slot. Ang Recomposition ay mas mura, lalo na kung ang karamihan sa mga function ay stable — ang kanilang mga parameter ay inihahambing sa pamamagitan ng equals, at nilalampasan ng Compose ang kanilang tawag. Para sa maximum na pagganap, dapat sikaping ang kaunting mga function hangga't maaari ay maapektuhan ng recomposition.
| Katangian | Composition | Recomposition |
|---|---|---|
| Kailan nangyayari | Isang beses, sa unang pagpapakita | Maraming beses, sa pagbabago ng data |
| Saklaw | Buong tree | Tanging mga binagong function |
| Paghahambing ng parameter | Hindi isinasagawa | Isinasagawa para sa skipping |
| Paglikha ng slot | Oo, lahat ng slot ay nilikha | Tanging para sa mga bagong node |
CompositionLocal — isang mekanismo ng implicit na pagpapadala ng data sa pamamagitan ng composition tree. Nalulutas nito ang problema kapag ang isang parameter ay kailangang ipadala sa pamamagitan ng dose-dosenang nested Composable function na hindi ito direktang ginagamit. Sa halip ng isang tahasang chain ng mga parameter, ang data ay itinakda sa itaas na antas at binabasa sa anumang nested function sa pamamagitan ng CompositionLocal.current.
Ang temang MaterialTheme — ang pinakakilalang halimbawa ng CompositionLocal. Lahat ng component ng Compose ay nagbabasa ng mga kulay, typography at mga hugis sa pamamagitan ng MaterialTheme.colorScheme, MaterialTheme.typography, MaterialTheme.shapes, nang hindi tumatanggap ng mga ito sa pamamagitan ng mga parameter. Ang developer ay maaaring lumikha ng sariling CompositionLocal para sa data tulad ng kasalukuyang user, mga setting ng lokalisasyon, o configuration ng screen.
Mahalagang limitasyon: ang CompositionLocal ay hindi dapat gamitin para sa madalas na nagbabagong data (posisyon ng scroll, text sa input field). Ang component na nagbabasa ng CompositionLocal ay ni-restart sa bawat pagbabago ng halaga, kaya para sa dynamic na data mas mainam na gumamit ng tahasang mga parameter o State. Ang CompositionLocal ay pinakamainam para sa configuration data na bihira o hindi nagbabago.
val LocalUser = compositionLocalOf<User?> { null }
@Composable
fun AppRoot(user: User, content: @Composable () -> Unit) {
CompositionLocalProvider(LocalUser.provides(user)) {
content()
}
}
@Composable
fun UserAvatar() {
val user = LocalUser.current // pagbabasa nang walang tahasang parameter
AsyncImage(model = user?.avatarUrl, contentDescription = "Avatar")
}
Ang CompositionLocalProvider ay lumilikha ng isang sakop ng visibility, kung saan ang LocalUser.current ay nagbabalik ng itinakdang halaga. Ang UserAvatar ay nagbabasa ng user nang walang tahasang pagpapadala ng parameter sa pamamagitan ng mga intermediate function. Ito ay lalong mahalaga sa malalalim na hierarchy kung saan ang data ay kailangan lamang sa ilang leaf node.
Mga madalas itanong
Ang pagbabago ng State habang Composition ay nag-iiskedyul ng bagong recomposition na isasagawa pagkatapos matapos ang kasalukuyan. Walang loop na nangyayari: ginagarantiyahan ng Compose na ang bawat recomposition ay isinasagawa sa isang hiwalay na transaksyon ng snapshot system.
Sa mga modernong device, ang Composition ng isang screen na may 50–100 Composable function ay tumatagal ng 1–5 ms. Inirerekomenda ng Google na manatili sa loob ng 16 ms bawat frame sa 60fps. Kung lumampas ang Composition sa limitasyong ito, gamitin ang LazyColumn o hatiin ang screen sa mas maliliit na function.
Ang direktang manu-manong pagsisimula ng Composition ay hindi posible — ito ay awtomatikong pinamamahalaan ng Composer. Gayunpaman, maaaring pilitin na mag-iskedyul ng recomposition sa pamamagitan ng pagbabago ng State o pagtawag sa invalidate() sa root composite, kung may access sa CompositionContext.
Ang View hierarchy — ay isang hindi nababagong tree ng Java object na nilikha nang isang beses. Composition — isang virtual tree na itinayong muli sa bawat pagbabago ng data. Iniimbak ng View ang estado nito sa mga instance variable, Composition — sa mga slot na nakatali sa posisyon ng tawag ng function.
Kung ang isang Composable function ay tumigil sa pagtawag (hal. ang kondisyong if ay naging false), tinatanggal ng Composition ang node nito at tinatawagan ang paglilinis ng DisposableEffect. Sa muling paglitaw (if ay naging true muli) isang bagong node ang nilikha — ang luma ay hindi na-restore.
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