Composition: суштина, изградња UI стабла у Compose-у

Аутор: IT Sectr Објављено: 2026-06-27 Време читања: 7 мин

Composition — централни процес у Jetpack Compose-у, током којег се од описних Composable функција гради живо UI стабло које се приказује на екрану. За разлику од View система у Android-у, где се распоред учитавао из XML-а и претварао у непроменљиве објекте, Composition ради као динамички систем: функције се извршавају, стварају слотове у меморији, формирају хијерархију чворова и повезују је са стањем. Према Google Android Developers, 2026, разумевање Composition-а је критично за оптимизацију перформанси Compose апликација.

Главне тачке

  • Composition — извршавање Composable функција за изградњу UI стабла
  • Слотови — меморијске ћелије које чувају параметре и стање сваке функције
  • Позиција у Compose-у (Positional Memorization) везује стање за место у коду
  • Први пролаз Composition ствара почетно UI стабло при покретању екрана
  • CompositionLocal преноси податке кроз стабло без експлицитних параметара

Шта је Composition у Jetpack Compose-у

Composition — процес извршавања Composable функција, чијим резултатом се формира унутрашња репрезентација корисничког интерфејса у облику стабла чворова. Сваки чвор овог стабла одговара или уграђеној компоненти (Text, Button, Image) или позиву прилагођене Composable функције. Composition не ствара директно Android View објекте — гради апстрактни опис који се затим обрађује фазама Layout и Drawing.

Кључна карактеристика Composition-а је његова могућност поновног покретања (restartability). Свака Composable функција у саставу композиције може се поново покренути у било ком тренутку, ако су се променили њени улазни параметри или објекти стања које је прочитала. Систем не покреће поново цело стабло — само оне функције које заиста зависе од промењених података.

Технички, Composition-ом управља Composer — унутрашњи мотор који Kotlin компајлер уграђује у сваку Composable функцију. Composer уписује у слотове (групе позиција) информације о томе које су функције позване, са којим параметрима и којим редоследом. При наредним позивима, Composer пореди нове податке са сачуваним и доноси одлуку о поновном покретању.

Како се гради UI стабло у процесу Composition-а

Процес изградње UI стабла почиње позивом методе setContent унутар Activity или Fragment-а. Ова метода ствара почетни Composition и покреће извршавање коренске Composable функције. Затим свака угнежђена Composable функција додаје своје чворове у стабло, формирајући хијерархију: Row садржи Text и Button, Column садржи Image и Card, и тако даље.

Сваки чвор стабла добија јединствени кључ позиције, заснован на његовом положају у изворном коду. Овај кључ се користи за идентификацију чвора при поновљеним извршавањима. Кључ позиције је разлог зашто редослед позивања Composable функција не треба да зависи од услова: ако су у једном извршавању позване A -> B, а у следећем B -> A, Compose неће моћи да упари старе и нове чворове.

kotlin
@Composable
fun AppScreen() {
    Column {                     // Чвор Column (позиција 1)
        HeaderSection()            // Чвор HeaderSection (позиција 2)
        ContentSection()           // Чвор ContentSection (позиција 3)
        FooterSection()            // Чвор FooterSection (позиција 4)
    }
}

@Composable
fun HeaderSection() {
    Row {                       // Чвор Row (позиција 2.1)
        Text("Наслов")         // Чвор Text (позиција 2.2)
        Icon(...)                // Чвор Icon (позиција 2.3)
    }
}

У овом примеру сваки позив добија позицију засновану на редоследу у коду. Column (позиција 1) садржи три подређена чвора (позиције 2, 3, 4). HeaderSection додаје још два подређена чвора (2.1, 2.2, 2.3). Ако у следећој рекомпозицији ContentSection буде позван пре HeaderSection-а, Composer неће моћи правилно да упари чворове — отуда правило: редослед позивања Composable функција мора бити стабилан.

Управљање стањем у Composition-у

Стање у Composition-у се управља преко објеката типа State<T>. Када Composable функција чита вредност из State-а преко делегираног својства (by), региструје зависност од тог State-а. При промени вредности, све функције које су прочитале овај State се обележавају за поновно покретање у следећој фази композиције.

Механизам регистрације зависности назива се систем снимака (snapshot system). Сваки пут када се State промени, снимак бележи све промене и обавештава Composer које функције зависе од овог State-а. Важно је разумети: читање State-а у коду који није Composable (нпр. у ламбди onClick) не региструје зависност — само читање унутар Composable функције или у ламбдама извршеним у контексту композиције.

Систем снимака ради транзакционо: неколико промена State-а у оквиру једног догађаја обједињује се у једну транзакцију, што спречава вишеструке рекомпозиције. Ово је посебно важно при обради гестова: током једног покрета мења се неколико State објеката, али Compose извршава само једну рекомпозицију.

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

    Column {
        Text(text)  // региструје зависност од text

        if (isVisible) {  // региструје зависност од isVisible
            TextField(value = text, onValueChange = { text = it })
        }

        Button(onClick = { isVisible = !isVisible }) {
            Text(if (isVisible) "Сакриј" else "Прикажи")
        }
    }
}

Промена text-а доводи до рекомпозиције само Column, Text и TextField-а. Button и услов isVisible остају непромењени. Таква изолованост рекомпозиције је кључна предност Compose-а у односу на системе који прецртавају цео екран. Свака Composable функција прати само оне State објекте које директно чита.

Composition vs Recomposition: кључне разлике

Composition (композиција) и Recomposition (рекомпозиција) — два различита режима извршавања Composable функција. Composition се дешава једном при креирању екрана: систем извршава све Composable функције са почетним вредностима и гради почетно UI стабло. Recomposition се дешава више пута при промени података: систем поново покреће само оне функције које зависе од промењеног стања.

Режим Composition активира све чворове стабла, додељује слотове за сваку функцију, региструје све потомке. Recomposition ради селективно: Compose пореди нове и старе вредности параметара сваке функције, и ако се нису промениле — функција се не извршава (skipping).

Composition и Recomposition се разликују по цени. Први Composition је скупљи, јер захтева потпуну изградњу стабла и доделу слотова. Recomposition је јефтинији, посебно ако је већина функција стабилна — њихови параметри се пореде по equals, а Compose прескаче њихов позив. За максималне перформансе треба тежити да што мање функција буде захваћено рекомпозицијом.

КарактеристикаCompositionRecomposition
Када се дешаваЈедном, при првом приказивањуВише пута, при промени података
ОбимЦело стаблоСамо измењене функције
Поређење параметараНе извршава сеИзвршава се за skipping
Креирање слотоваДа, сви слотови се креирајуСамо за нове чворове

CompositionLocal: пренос података кроз стабло

CompositionLocal — механизам имплицитног преноса података кроз стабло композиције. Решава проблем када параметар треба пренети кроз десетине угнежђених Composable функција које га директно не користе. Уместо експлицитног ланца параметара, подаци се постављају на горњем нивоу и читају у било којој угнежђеној функцији кроз CompositionLocal.current.

Тема MaterialTheme — најпознатији пример CompositionLocal-а. Све компоненте Compose-а читају боје, типографију и облике кроз MaterialTheme.colorScheme, MaterialTheme.typography, MaterialTheme.shapes, не примајући их кроз параметре. Програмер може креирати сопствене CompositionLocal за податке као што су тренутни корисник, подешавања локализације или конфигурација екрана.

Важно ограничење: CompositionLocal не треба користити за податке који се често мењају (положај скроловања, текст у пољу за унос). Компонента која чита CompositionLocal се поново покреће при свакој промени вредности, стога је за динамичке податке боље користити експлицитне параметре или State. CompositionLocal је оптималан за конфигурационе податке који се ретко или никад не мењају.

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  // читање без експлицитног параметра
    AsyncImage(model = user?.avatarUrl, contentDescription = "Avatar")
}

CompositionLocalProvider ствара област видљивости, унутар које LocalUser.current враћа постављену вредност. UserAvatar чита корисника без експлицитног преноса параметра кроз посредне функције. Ово је посебно вредно у дубоким хијерархијама, где су подаци потребни само у неколико листова чворова.

Често постављана питања

Шта се дешава ако се State промени током Composition-а?

Промена State-а током Composition-а планира нову рекомпозицију која ће се извршити након завршетка тренутне. Не долази до петље: Compose гарантује да се свака рекомпозиција извршава у посебној трансакцији snapshot система.

Колико времена траје Composition сложеног екрана?

На савременим уређајима Composition екрана са 50–100 Composable функција траје 1–5 ms. Google препоручује уклапање у 16 ms за кадар од 60fps. Ако Composition премашује ово ограничење, користите LazyColumn или разбијте екран на мање функције.

Може ли се Composition покренути ручно?

Директно ручно покретање Composition-а није могуће — њиме аутоматски управља Composer. Међутим, може се присилно заказати рекомпозиција променом State-а или позивањем invalidate() на коренском композиту, ако постоји приступ CompositionContext-у.

По чему се Composition разликује од View хијерархије у класичном Android-у?

View хијерархија — непроменљиво стабло Java објеката које се креира једном. Composition — виртуелно стабло које се преграђује при свакој промени података. View чува своје стање у променљивама инстанце, Composition — у слотовима везаним за позицију позива функције.

Како Composition обрађује уклањање чворова?

Ако Composable функција престане да се позива (нпр. услов if постане false), Composition уклања њен чвор и позива чишћење DisposableEffect-а. При поновном појављивању (if поново true) креира се нови чвор — стари се не обнавља.

Закључак

  • Composition — процес извршавања Composable функција за изградњу UI стабла са везивањем за стање
  • Composer управља слотовима, бележи позиве функција и пореди параметре при рекомпозицији
  • Систем снимака региструје зависности функција од State-а и обједињује промене у трансакције
  • Composition се извршава једном при покретању, Recomposition — при промени података
  • CompositionLocal преноси конфигурационе податке кроз стабло без експлицитног ланца параметара
  • Позиција позива функције служи као њен јединствени идентификатор у стаблу композиције
  • Препорука: правите Composable функције малим, са непроменљивим параметрима за ефикасан skipping

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође