Composition: podstata, budování UI stromu v Compose

Autor: IT Sectr Publikováno: 2026-06-27 Doba čtení: 7 min

Composition — je ústřední proces v Jetpack Compose, během kterého se z popisných Composable funkcí buduje živý UI strom zobrazovaný na obrazovce. Na rozdíl od systému View v Androidu, kde se rozvržení načítalo z XML a převádělo na neměnné objekty, Composition funguje jako dynamický systém: funkce se provádějí, vytvářejí sloty v paměti, tvoří hierarchii uzlů a propojují ji se stavem. Podle Google Android Developers, 2026 je porozumění Composition kriticky důležité pro optimalizaci výkonu Compose aplikací.

Hlavní body

  • Composition — provádění Composable funkcí pro budování UI stromu
  • Sloty — paměťové buňky ukládající parametry a stav každé funkce
  • Pozice v Compose (Positional Memorization) váže stav k místu v kódu
  • První průchod Composition vytváří počáteční UI strom při spuštění obrazovky
  • CompositionLocal předává data stromem bez explicitních parametrů

Co je Composition v Jetpack Compose

Composition — je proces provádění Composable funkcí, jehož výsledkem je vnitřní reprezentace uživatelského rozhraní ve formě stromu uzlů. Každý uzel tohoto stromu odpovídá buď vestavěné komponentě (Text, Button, Image), nebo volání vlastní Composable funkce. Composition přímo nevytváří Android View objekty — buduje abstraktní popis, který je poté zpracováván fázemi Layout a Drawing.

Klíčovou vlastností Composition je jeho znovuspuštění (restartability). Každá Composable funkce v rámci kompozice může být kdykoli znovu spuštěna, pokud se změní její vstupní parametry nebo stavové objekty, které přečetla. Systém nespouští znovu celý strom — pouze ty funkce, které skutečně závisí na změněných datech.

Technicky je Composition řízen prostřednictvím Composer — interního enginu, který Kotlin kompilátor vkládá do každé Composable funkce. Composer zapisuje do slotů (skupin pozic) informace o tom, které funkce byly volány, s jakými parametry a v jakém pořadí. Při následujících voláních Composer porovnává nová data s uloženými a rozhoduje o znovuspuštění.

Jak se buduje UI strom v procesu Composition

Proces budování UI stromu začíná voláním metody setContent uvnitř Activity nebo Fragment. Tato metoda vytváří počáteční Composition a spouští provádění kořenové Composable funkce. Poté každá vnořená Composable funkce přidává své uzly do stromu, čímž vytváří hierarchii: Row obsahuje Text a Button, Column obsahuje Image a Card, a tak dále.

Každý uzel stromu získává unikátní klíč pozice založený na jeho poloze ve zdrojovém kódu. Tento klíč se používá k identifikaci uzlu při opakovaných prováděních. Klíč pozice je důvodem, proč by pořadí volání Composable funkcí nemělo záviset na podmínkách: pokud v jednom provedení bylo voláno A -> B a v následujícím B -> A, Compose nebude schopen přiřadit staré a nové uzly.

kotlin
@Composable
fun AppScreen() {
    Column {                     // Uzel Column (pozice 1)
        HeaderSection()            // Uzel HeaderSection (pozice 2)
        ContentSection()           // Uzel ContentSection (pozice 3)
        FooterSection()            // Uzel FooterSection (pozice 4)
    }
}

@Composable
fun HeaderSection() {
    Row {                       // Uzel Row (pozice 2.1)
        Text("Název")         // Uzel Text (pozice 2.2)
        Icon(...)                // Uzel Icon (pozice 2.3)
    }
}

V tomto příkladu každé volání získává pozici založenou na pořadí v kódu. Column (pozice 1) obsahuje tři podřízené uzly (pozice 2, 3, 4). HeaderSection přidává další dva podřízené uzly (2.1, 2.2, 2.3). Pokud je v následující rekompozici ContentSection volán před HeaderSection, Composer nebude schopen správně přiřadit uzly — odtud pravidlo: pořadí volání Composable funkcí musí být stabilní.

Správa stavu v Composition

Stav v Composition je spravován prostřednictvím objektů typu State<T>. Když Composable funkce čte hodnotu ze State pomocí delegované vlastnosti (by), registruje závislost na tomto State. Při změně hodnoty jsou všechny funkce, které tento State přečetly, označeny pro znovuspuštění v další fázi kompozice.

Mechanismus registrace závislostí se nazývá snapshot systém. Pokaždé, když se State změní, snapshot zaznamená všechny změny a upozorní Composer, které funkce na tomto State závisí. Je důležité pochopit: čtení State v ne-Composable kódu (např. v lambdě onClick) neregistruje závislost — pouze čtení uvnitř Composable funkce nebo v lambdách provedených v kontextu kompozice.

Snapshot systém pracuje transakčně: několik změn State v rámci jedné události se sloučí do jedné transakce, což zabraňuje vícenásobným rekompozicím. To je zvláště důležité při zpracování gest: během jednoho pohybu se změní několik State objektů, ale Compose provede pouze jednu rekompozici.

kotlin
@Composable
fun StateExample() {
    var text by remember { mutableStateOf("Hello") }
    var isVisible by remember { mutableStateOf(true) }

    Column {
        Text(text)  // registruje závislost na text

        if (isVisible) {  // registruje závislost na isVisible
            TextField(value = text, onValueChange = { text = it })
        }

        Button(onClick = { isVisible = !isVisible }) {
            Text(if (isVisible) "Skrýt" else "Zobrazit")
        }
    }
}

Změna textu vede k rekompozici pouze Column, Text a TextField. Button a podmínka isVisible zůstávají nezměněny. Taková izolace rekompozice je klíčovou výhodou Compose oproti systémům, které překreslují celou obrazovku. Každá Composable funkce sleduje pouze ty State objekty, které přímo čte.

Composition vs Recomposition: klíčové rozdíly

Composition (kompozice) a Recomposition (rekompozice) — jsou dva různé režimy provádění Composable funkcí. Composition probíhá jednou při vytvoření obrazovky: systém provede všechny Composable funkce s počátečními hodnotami a vytvoří počáteční UI strom. Recomposition probíhá opakovaně při změně dat: systém znovu spouští pouze ty funkce, které závisí na změněném stavu.

Režim Composition aktivuje všechny uzly stromu, alokuje sloty pro každou funkci, registruje všechny potomky. Recomposition pracuje selektivně: Compose porovnává nové a staré hodnoty parametrů každé funkce, a pokud se nezměnily — funkce se neprovádí (skipping).

Composition a Recomposition se liší náklady. První Composition je dražší, protože vyžaduje úplné vytvoření stromu a alokaci slotů. Recomposition je levnější, zejména pokud je většina funkcí stabilních — jejich parametry se porovnávají pomocí equals a Compose přeskočí jejich volání. Pro maximální výkon je třeba usilovat o to, aby co nejméně funkcí bylo zasaženo rekompozicí.

VlastnostCompositionRecomposition
Kdy probíháJednou, při prvním zobrazeníOpakovaně, při změně dat
RozsahCelý stromPouze změněné funkce
Porovnání parametrůNeprovádí seProvádí se pro skipping
Vytváření slotůAno, všechny sloty se vytvářejíPouze pro nové uzly

CompositionLocal: předávání dat stromem

CompositionLocal — mechanismus implicitního předávání dat stromem kompozice. Řeší problém, když je parametr třeba předat přes desítky vnořených Composable funkcí, které ho přímo nepoužívají. Místo explicitního řetězce parametrů jsou data nastavena na horní úrovni a čtena v libovolné vnořené funkci pomocí CompositionLocal.current.

Téma MaterialTheme — nejznámější příklad CompositionLocal. Všechny komponenty Compose čtou barvy, typografii a tvary přes MaterialTheme.colorScheme, MaterialTheme.typography, MaterialTheme.shapes, aniž by je přijímaly přes parametry. Vývojář může vytvářet vlastní CompositionLocal pro data jako aktuální uživatel, nastavení lokalizace nebo konfiguraci obrazovky.

Důležité omezení: CompositionLocal by se neměl používat pro často se měnící data (pozice posouvání, text v poli vstupu). Komponenta čtoucí CompositionLocal se restartuje při každé změně hodnoty, proto je pro dynamická data lepší používat explicitní parametry nebo State. CompositionLocal je optimální pro konfigurační data, která se mění zřídka nebo vůbec.

kotlin
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  // čtení bez explicitního parametru
    AsyncImage(model = user?.avatarUrl, contentDescription = "Avatar")
}

CompositionLocalProvider vytváří oblast viditelnosti, uvnitř které LocalUser.current vrací nastavenou hodnotu. UserAvatar čte uživatele bez explicitního předávání parametru přes zprostředkující funkce. To je zvláště cenné v hlubokých hierarchiích, kde jsou data potřebná pouze v několika listových uzlech.

Často kladené otázky

Co se stane, když se State změní během Composition?

Změna State během Composition naplánuje novou rekompozici, která se provede po dokončení té současné. Nedochází k zacyklení: Compose garantuje, že každá rekompozice se provádí v samostatné transakci snapshot systému.

Jak dlouho trvá Composition složité obrazovky?

Na moderních zařízeních trvá Composition obrazovky s 50–100 Composable funkcemi 1–5 ms. Google doporučuje vejít se do 16 ms pro snímek při 60fps. Pokud Composition překračuje tento limit, použijte LazyColumn nebo rozdělte obrazovku na menší funkce.

Lze Composition spustit ručně?

Přímé ruční spuštění Composition není možné — je automaticky řízeno Composer. Lze však vynutit naplánování rekompozice změnou State nebo voláním invalidate() na kořenovém kompozitu, pokud je přístup k CompositionContext.

Čím se Composition liší od hierarchie View v klasickém Androidu?

Hierarchie View — je neměnný strom Java objektů, který se vytváří jednou. Composition — virtuální strom, který se přestavuje při každé změně dat. View uchovává svůj stav v instančních proměnných, Composition — v slotech vázaných na pozici volání funkce.

Jak Composition zpracovává odstraňování uzlů?

Pokud Composable funkce přestane být volána (např. podmínka if se stane false), Composition odstraní její uzel a zavolá vyčištění DisposableEffect. Při opětovném objevení (if se stane znovu true) se vytvoří nový uzel — starý se neobnovuje.

Shrnutí

  • Composition — proces provádění Composable funkcí pro budování UI stromu vázaného na stav
  • Composer spravuje sloty, zaznamenává volání funkcí a porovnává parametry při rekompozici
  • Snapshot systém registruje závislosti funkcí na State a slučuje změny do transakcí
  • Composition se provádí jednou při startu, Recomposition — při změně dat
  • CompositionLocal předává konfigurační data stromem bez explicitního řetězce parametrů
  • Pozice volání funkce slouží jako její unikátní identifikátor ve stromu kompozice
  • Doporučení: vytvářejte malé Composable funkce s neměnnými parametry pro efektivní skipping

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také