Jetpack Compose: podstawy, funkcje Composable i State

Autor: IT Sectr Opublikowano: 2026-02-21 Czas czytania: 8 min

Jetpack Compose — nowoczesny deklaratywny framework UI od Google do tworzenia aplikacji na Androida, wydany w stabilnej wersji 1.0 w lipcu 2021 roku. Compose zastępuje imperatywne znaczniki XML i system View funkcjami Kotlin z adnotacją @Composable. Według Google I/O (2025), Compose jest używany w 55% nowych projektów na Androida, a średni rozmiar kodu UI zmniejsza się o 30–50% w porównaniu z XML. Framework automatycznie przerysowuje tylko zmienione części ekranu przy zmianie State, eliminując ręczne wywoływanie notifyDataSetChanged czy findViewById.

Najważniejsze

  • Jetpack Compose — deklaratywny framework UI Google dla Androida w Kotlin (funkcje @Composable zamiast znaczników XML).
  • @Composable — adnotacja funkcji opisującej część UI, która może przyjmować parametry i czytać State.
  • State i MutableState — mechanizm reaktywności: przy zmianie State Compose restartuje (recompose) tylko zależne funkcje Composable.
  • remember — funkcja buforowania wartości między rekompozycjami; bez niej State jest resetowany przy każdej aktualizacji.
  • Modifier — łańcuch ustawień (padding, size, clickable, background), zarządzający wyglądem i zachowaniem Composable.

Czym jest Jetpack Compose?

Jetpack Compose — framework UI Google zbudowany na zasadach programowania reaktywnego. Zamiast Activity z układami XML, FragmentManager i ViewBinding, programista opisuje interfejs poprzez funkcje Kotlin z adnotacją @Composable. Compose nie używa LayoutInflater — UI to czyste funkcje Kotlin, kompilowane do kodu bajtowego. Framework składa się z kilku bibliotek: Compose UI (podstawowe komponenty Text, Button, Column, Row), Compose Foundation (Material Design, Gesty, Focus), Compose Material3 (Material You z Dynamic Colors) i Compose Runtime (State, Side Effects, Coroutines). Compose działa na Android API 21+ (Android 5.0) i jest w pełni kompatybilny z istniejącym kodem na View/XML poprzez ComposeView — adapter AndroidView.

Compose vs View System

View System (2008) wykorzystuje hierarchię obiektów View z ręcznym zarządzaniem: programista tworzy układ XML, znajduje View przez findViewById, implementuje Adapter dla RecyclerView i wywołuje notifyDataSetChanged przy zmianie danych. Compose opisuje UI funkcyjnie: przy zmianie stanu framework restartuje (recompose) tylko zmienione funkcje Composable, oblicza diff i stosuje minimalne zmiany do Canvas. Wydajność Compose jest porównywalna z View System, a w scenariuszach ze złożonymi listami (LazyColumn) często przewyższa RecyclerView dzięki pomijaniu zbędnych elementów przez parametr key. W IT Sectr Compose jest używany w nowych modułach aplikacji Android z minSdk 24+.

Funkcje Composable: bloki budulcowe UI

@Composable — adnotacja zamieniająca zwykłą funkcję Kotlin w blok budulcowy UI. Funkcje Composable mogą wywoływać inne funkcje Composable, tworząc drzewo komponentów. W przeciwieństwie do View, funkcje Composable domyślnie nie mają stanu — są stateless i przerysowywane przy każdej zmianie parametrów wejściowych lub State. Kompilator (Compose Compiler) transformuje funkcje @Composable w kod, który może być przerwany i wznowiony (positional memoization) — pozwala to Compose restartować tylko zmienione części bez pełnego przebudowywania drzewa.

kotlin
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@Composable
fun UserProfile(name: String, avatarUrl: String) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        AsyncImage(
            model = avatarUrl,
            contentDescription = "User avatar",
            modifier = Modifier.size(48.dp)
        )
        Spacer(modifier = Modifier.width(12.dp))
        Text(
            text = name,
            style = MaterialTheme.typography.titleMedium
        )
    }
}

Funkcja UserProfile przyjmuje name i avatarUrl jako parametry, buduje wiersz z awatarem i nazwą. Modifier.fillMaxWidth() rozciąga komponent na całą szerokość, .padding(16.dp) dodaje odstępy. MaterialTheme.typography.titleMedium używa systemowego stylu Material 3. Przy zmianie parametrów name lub avatarUrl Compose restartuje UserProfile — ponowne tworzenie komponentu z nowymi wartościami.

State i Recomposition w Jetpack Compose

State w Compose — to dowolna wartość, której zmiana powoduje rekompozycję (restart) zależnych funkcji @Composable. Podstawowym sposobem jest mutableStateOf(), tworzący MutableState<T> z obsługą systemu snapshotów Compose. Snapshot — mechanizm śledzenia zmian: przy zapisie do State Compose oznacza bieżący Snapshot jako dirty, a planista rekompozycji restartuje tylko funkcje Composable czytające ten State. Dla kolekcji observable używaj mutableStateListOf() i mutableStateMapOf(). Compose obsługuje State z komponentów Lifecycle-Aware przez collectAsState() dla Kotlin Flow i observeAsState() dla LiveData.

kotlin
@Composable
fun LikeButton() {
    var liked by remember { mutableStateOf(false) }
    var count by remember { mutableStateOf(42) }
    
    Button(
        onClick = {
            liked = !liked
            if (liked) count++ else count--
        },
        colors = ButtonDefaults.buttonColors(
            containerColor = if (liked) MaterialTheme.colorScheme.primary
                else MaterialTheme.colorScheme.surfaceVariant
        )
    ) {
        Text("♥ $count")
    }
}

Kod tworzy przycisk «Like» ze stanem liked (Boolean) i count (Int), przechowywanymi przez mutableStateOf(). Po naciśnięciu liked jest odwracany, licznik zwiększa/zmniejsza się — Compose automatycznie restartuje LikeButton. by delegate pozwala używać State jak zwykłej zmiennej: liked = !liked zamiast liked.value = !liked.value. Kolor przycisku zmienia się reaktywnie między primary (polubione) a surfaceVariant (niepolubione).

remember: buforowanie między rekompozycjami

remember — funkcja Compose buforująca wartość między rekompozycjami. Bez remember każdy restart funkcji Composable tworzy nowy stan (mutableStateOf) — to psuje logikę aplikacji: przy obrocie ekranu lub zmianie nadrzędnego State licznik zostanie zresetowany. remember przyjmuje lambdę-kalkulator i oblicza wartość tylko przy pierwszej kompozycji; przy kolejnych zwraca buforowany wynik. Do resetowania bufora używaj remember(key) — klucz określa, kiedy przeliczyć wartość. remember(key1, key2) przelicza przy zmianie dowolnego klucza. Dla długożyjących stanów (przetrwających obrót ekranu) używaj rememberSaveable — odpowiednik remember z zapisem w Bundle przez SavedStateHandle.

kotlin
@Composable
fun TimerScreen() {
    var seconds by rememberSaveable { mutableStateOf(0) }
    
    LaunchedEffect(Unit) {
        while (true) {
            delay(1000)
            seconds++
        }
    }
    
    Column(
        modifier = Modifier.fillMaxSize().padding(32.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "Upłynęło: ${seconds}s",
            style = MaterialTheme.typography.displayMedium
        )
    }
}

rememberSaveable zachowuje seconds przy obrocie ekranu (zmiana konfiguracji). LaunchedEffect uruchamia korutynę, inkrementującą seconds co sekundę. Przy rekompozycji TimerScreen (co sekundę) seconds nie jest resetowany dzięki rememberSaveable. Używaj zwykłego remember dla stanu, który nie powinien przetrwać zmian konfiguracji (np. flagi animacji).

Modifier: łańcuch ustawień Composable

Modifier — niemutowalny obiekt-kontener implementujący wzorzec Builder do ustawiania wyglądu, zachowania i układu komponentów Composable. Każde wywołanie metody Modifier (.padding(), .width(), .clickable(), .background()) zwraca nowy Modifier z dodanym elementem. Kolejność modyfikatorów ma znaczenie: .padding(16.dp).clickable { } — odstęp jest stosowany przed obsługą kliknięcia, clickable śledzi cały obszar z uwzględnieniem odstępu. .clickable { }.padding(16.dp) — klikalny jest cały obszar przed odstępem, odstęp przesuwa zawartość do środka. Modifier obsługuje implementacje niestandardowe przez then(otherModifier) i compositionLocal do dostępu do ustawień nadrzędnych.

kotlin
@Composable
fun CardExample() {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
            .clickable { println("Kliknięto kartę") },
        elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
        colors = CardDefaults.cardColors(
            containerColor = MaterialTheme.colorScheme.surfaceVariant
        )
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text("Jetpack Compose", style = MaterialTheme.typography.titleLarge)
            Spacer(modifier = Modifier.height(8.dp))
            Text(
                "Deklaratywny UI dla Androida z State i Modifier",
                style = MaterialTheme.typography.bodyMedium
            )
        }
    }
}

CardExample demonstruje łańcuch Modifier: fillMaxWidth + padding + clickable. Card — komponent Material3 z własnymi ustawieniami elevation i colors. Zagnieżdżony Column ma wewnętrzny padding 16dp. Compose Material3 automatycznie dostosowuje kolory do Dynamic Color (Material You) na Android 12+. Card jest jednym z 30+ wbudowanych komponentów Material3 w Compose.

State hoisting i architektura Compose

State hoisting — wzorzec podnoszenia stanu z funkcji Composable do jej wywołującego, czyniący funkcję stateless. Komponent stateless przyjmuje dane i callbacki przez parametry, nie posiadając własnego State. Zwiększa to możliwość ponownego użycia i testowania: komponent można wywołać z różnymi State i przetestować w preview. Google zaleca architekturę: ViewModel + StateFlow (lub MutableStateFlow) + collectAsState() w Compose. ViewModel podnosi stan na poziom ekranu, Compose wyświetla. Efekty uboczne (LaunchedEffect, DisposableEffect) obsługują jednorazowe zdarzenia.

KomponentObowiązekTechnologia
ViewModelPrzechowywanie State, logika biznesowaStateFlow, MutableStateFlow
Screen ComposableOrganizacja ekranu, State hoistingcollectAsState(), Scaffold, LazyColumn
Stateless ComponentUI bez stanu, czyste wyświetlanie@Composable parametry + lambdy
Side EffectJednorazowe działania (snackbar, nawigacja)LaunchedEffect, SnackbarHostState

Często zadawane pytania

Czym Jetpack Compose różni się od układów XML?

Układy XML są imperatywne: LayoutInflater ładuje XML, findViewById znajduje View, programista ręcznie aktualizuje tekst/listy. Compose jest deklaratywny: UI opisuje się funkcjami Kotlin @Composable, a framework automatycznie przerysowuje tylko zmienione części przy zmianie State. Compose zmniejsza objętość kodu UI o 30–50% i nie używa XML.

Czy potrzebna jest osobna biblioteka do nawigacji w Compose?

Tak, Google udostępnia Navigation Compose — bibliotekę do deklaratywnej nawigacji między ekranami. NavController zarządza stosem tras, composable() rejestruje ekrany, navArgument przekazuje parametry. Alternatywy: Voyager (społeczność) i Decompose (Badoo). Navigation Compose — oficjalny standard z obsługą deep links i argumentów type-safe.

Czym jest Modifier w Jetpack Compose?

Modifier — niemutowalny kontener wzorców stylowania (padding, size, clickable, background, border, clip), stosowanych do komponentów Composable. Każde wywołanie zwraca nowy Modifier z dodanym elementem. Kolejność jest ważna: .padding().clickable() stosuje odstęp przed kliknięciem, .clickable().padding() — odwrotnie. Modifier to podstawowy sposób dostosowywania komponentów Compose.

Czy Compose działa na wszystkich wersjach Androida?

Jetpack Compose obsługuje Android API 21+ (Android 5.0 Lollipop) przez Compose Compiler i Compose BOM. Material 3 (Dynamic Colors) jest dostępny na Android 12+; na starszych wersjach używana jest paleta fallback. W nowych projektach Apple zaleca minSdk 24+ (Android 7.0), co jest w pełni obsługiwane przez Compose.

Jak testować komponenty Compose?

Google udostępnia Compose UI Test — bibliotekę do testowania na JVM (Desktop) i emulatorze. Główne funkcje: composeTestRule.setContent { } do renderowania komponentu, onNodeWithText() do wyszukiwania elementów, performClick()/performTextInput() do akcji. Testy Espresso są kompatybilne z Compose przez ComposeTestRule, ale Compose UI Test jest preferowanym i szybszym podejściem.

Podsumowanie

  • Jetpack Compose — deklaratywny framework UI Google dla Androida z funkcjami Kotlin @Composable zamiast XML (stabilny od 2021).
  • @Composable — adnotacja zamieniająca funkcję Kotlin w komponent UI; drzewo funkcji Composable zastępuje hierarchię View.
  • State i mutableStateOf — podstawa reaktywności Compose przez system Snapshot; rekompozycja dotyczy tylko zależnych funkcji.
  • remember buforuje wartość między rekompozycjami; rememberSaveable zachowuje State przy zmianach konfiguracji.
  • Modifier — łańcuch ustawień (padding, size, clickable, background) tworzący niemutowalny kontener; kolejność modyfikatorów jest ważna.
  • State hoisting — wzorzec podnoszenia stanu w górę dla komponentów stateless; ViewModel + StateFlow + collectAsState() — zalecana architektura.
  • Material 3 z Dynamic Colors (Android 12+) — standardowy motyw Compose z automatycznym dostosowaniem do tapety urządzenia.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również