composable(): co to je, NavHost a směrování v Jetpack Compose

Autor: IT Sectr Publikováno: 2026-06-30 Doba čtení: 9 min

composable() — je funkce knihovny Navigation Compose, která registruje obrazovku v NavHost a propojuje URL trasu s rozložením Compose. Když navigace přejde na zadanou trasu, Jetpack Compose zavolá odpovídající composable funkci a zobrazí ji jako aktuální obrazovku. Na rozdíl od FragmentManager nebo navigace založené na Intent, composable() pracuje na úrovni jedné Activity a je plně spravována přes Kotlin DSL. Podle údajů Android Developers (2025), více než 73% moderních Android aplikací postavených na Jetpack Compose používá právě Navigation Compose pro organizaci změny obrazovek.

Hlavní body

  • composable() — funkce registrace obrazovky v NavHost knihovny Navigation Compose.
  • Trasa — každá obrazovka je identifikována textovou trasou předávanou jako první argument.
  • Parametry — composable() podporuje argumenty přes NavArgument, včetně povinných a volitelných.
  • Vnoření — vnořená navigace je podporována přes vnořené NavHost s oddělenými grafy tras.
  • Výkon — composable() používá línou inicializaci: obrazovka se vytváří až při prvním přechodu.

Co je composable() v NavHost

composable() — je rozšiřující funkce (extension function) objektu NavHost. Kotlin DSL umožňuje volat ji uvnitř bloku NavHost pro deklarativní popis všech obrazovek aplikace. Každé volání vytváří záznam v navigačním grafu, spojující textovou trasu s composable funkcí. Když uživatel přejde na určitou trasu, NavHost zobrazí odpovídající composable jako aktuální obrazovku a skryje předchozí.

Knihovna Navigation Compose byla představena Googlem v roce 2021 jako alternativa k navigaci založené na Fragment pro Jetpack Compose. Hlavní výhoda — plná kompatibilita s paradigmatem Compose: composable() pracuje ve stejném životním cyklu jako ostatní komponenty Compose, bez potřeby FragmentManager nebo transakcí. Tím se eliminuje třída chyb spojených s nesouladem životního cyklu Fragment a Compose.

Každý composable() přijímá textovou trasu (route) a lambda funkci, která obdrží objekt NavBackStackEntry a vrací Composable UI. Uvnitř lambdy lze přistupovat k NavController přes volání navController z rozsahu, což umožňuje organizovat přechody na jiné obrazovky. Taková architektura činí navigaci explicitní a předvídatelnou.

kotlin
@Composable
fun AppNavigation() {
    val navController = rememberNavController()
    
    NavHost(
        navController = navController,
        startDestination = "home"
    ) {
        composable("home") {
            HomeScreen(
                onNavigateToProfile = {
                    navController.navigate("profile")
                }
            )
        }
        composable("profile") {
            ProfileScreen(
                onBack = { navController.popBackStack() }
            )
        }
    }
}

Jak funguje composable(): klíče a parametry

Každé volání composable() vytváří ve vnitřním grafu NavHost uzel s jedinečným identifikátorem trasy. Když NavController provede navigate(), knihovna porovná požadovanou trasu se všemi registrovanými composable uzly a najde odpovídající. Po shodě se vytvoří NavBackStackEntry, který je umístěn na navigační zásobník a spustí se kompozice UI.

Vnitřní implementace composable() využívá mechanismus líné inicializace: kompozice obrazovky nastává až v okamžiku prvního přechodu na tuto trasu. To znamená, že obrazovky, na které uživatel nikdy nepřešel, nezabírají paměť a nevykonávají žádný kód. Tento přístup výrazně zlepšuje výkon aplikací s velkým počtem obrazovek.

Parametr key v composable() umožňuje řídit znovuvytvoření obrazovky. Ve výchozím nastavení se composable při opakovaném přechodu na stejnou trasu znovu nevytváří — NavHost používá existující záznam v zásobníku. Pokud je však key předán a změní se, NavHost vytvoří novou instanci composable funkce. To je užitečné pro obrazovky s dynamickými daty, kde je třeba vynutit obnovení stavu při opětovném otevření.

kotlin
val NavGraphBuilder.Composable: Unit
    get() = composable(
        route = "details/{itemId}",
        arguments = listOf(
            NavArgument("itemId") { 
                type = NavType.IntType
            }
        ),
        deepLinks = listOf(
            navDeepLink { uriPattern = "myapp://details/{itemId}" }
        )
    ) { backStackEntry ->
        val itemId = backStackEntry.arguments?.getInt("itemId") ?: 0
        DetailsScreen(itemId = itemId)
    }

Předávání argumentů přes composable()

composable() podporuje flexibilní systém argumentů přes parametr arguments. Každý argument je popsán objektem NavArgument, který definuje typ, výchozí hodnotu a povinnost. Argumenty se předávají v trase jako parametry cesty (přes složené závorky) nebo parametry dotazu (přes otazník).

Parametry cesty jsou uvedeny přímo v šabloně trasy: "profile/{userId}". Při přechodu na trasu "profile/42" NavHost automaticky extrahuje hodnotu 42 a zpřístupní ji přes backStackEntry.arguments. Parametry dotazu se přidávají za otazník: "search?query={text}" a jsou také automaticky parsovány knihovnou.

Při extrahování argumentů je důležité zkontrolovat povinnost parametru přes NavType.isNullableAllowed a poskytnout výchozí hodnoty přes NavArgument defaultValue. Pokud povinný parametr chybí, Navigation Compose generuje výjimku IllegalArgumentException, což zabraňuje neviditelným chybám s nesprávnými trasami.

Typ argumentuNavTypePříklad v trase
IntNavType.IntType"item/{id}"
StringNavType.StringType"user/{name}"
BooleanNavType.BoolType"filter?enabled={value}"
FloatNavType.FloatType"map/{lat}/{lon}"
LongNavType.LongType"article/{timestamp}"

Pro předávání složitých objektů se doporučuje použít NavType.ParcelableType nebo NavType.SerializableType. Google však radí minimalizovat velikost předávaných dat — je lepší předat identifikátor a načíst objekt podle identifikátoru uvnitř obrazovky. To zabraňuje problémům s velkými serializovanými daty a zjednodušuje zpracování změn konfigurace.

kotlin
data class Profile(val id: Int, val name: String) : Parcelable

            // Navigujte s minimálními daty
navController.navigate("profile/42")

            // Získejte argumenty na obrazovce
composable(
    route = "profile/{userId}",
    arguments = listOf(
        NavArgument("userId") { type = NavType.IntType }
    )
) { backStackEntry ->
    val userId = backStackEntry.arguments?.getInt("userId") ?: 0
    ProfileDetailScreen(userId = userId)
}

Vnořená navigace s composable()

V reálných aplikacích je často nutné organizovat vnořené navigační grafy — například samostatný zásobník obrazovek uvnitř karty BottomNavigation. composable() podporuje vnoření přes mechanismus vnořených NavHost: uvnitř composable obrazovky lze deklarovat vlastní NavHost s nezávislým zásobníkem tras.

Každý vnořený NavHost má vlastní NavController a back stack. To znamená, že navigace uvnitř karty neovlivňuje navigaci v jiných kartách — uživatel může volně přepínat mezi kartami, aniž by ztratil historii přechodů uvnitř každé z nich. Taková architektura se nazývá Scoped Navigation a je doporučována Googlem pro aplikace se složitou víceúrovňovou navigací.

Při implementaci vnořené navigace je důležité správně spravovat stav NavController: každý vnořený NavHost by měl ukládat svůj rememberNavController v rozsahu composable funkce. Podle údajů Android Developer Summit 2024, více než 40% aplikací na Jetpack Compose se třemi a více kartami používá architekturu vnořených NavHost pro izolaci navigace mezi moduly.

kotlin
// Hlavní NavHost s kartami
composable("tabs") {
    MainTabsScreen { tab ->
        when (tab) {
            Tab.Home -> HomeNavGraph()
            Tab.Search -> SearchNavGraph()
        }
    }
}

// Vnořený graf v kartě Home
@Composable
fun HomeNavGraph() {
    val navController = rememberNavController()
    NavHost(
        navController = navController,
        startDestination = "home_feed"
    ) {
        composable("home_feed") { FeedScreen() }
        composable("home_detail/{postId}") { PostDetailScreen() }
    }
}

Srovnání composable() s navigací Intent

Před Jetpack Compose standardní způsob navigace v Androidu používal Intent a FragmentManager. Intent — systémová zpráva, která spouští novou Activity, což znamená znovuvytvoření celého View stromu. Na rozdíl od toho composable() pracuje uvnitř jedné Activity a jednoduše nahrazuje část Compose stromu, což je výrazně rychlejší a paměťově efektivnější.

Hlavní rozdíly mezi composable() a navigací založenou na Intent:

  • Rychlost — composable() přepíná obrazovky v milisekundách bez znovuvytvoření Activity, Intent vyžaduje restartování Activity.
  • Animace — v Navigation Compose se přechodové animace nastavují deklarativně přes AnimatedNavHost, bez potřeby overridePendingTransition.
  • Sdílený stav — composable() pracuje ve sdíleném rozsahu ViewModel, což zjednodušuje předávání dat mezi obrazovkami bez Intent extras.
Vlastnostcomposable()Intent / Fragment
ArchitekturaSingle Activity, Compose stromMulti Activity, Fragment zásobníky
Přenos datparametry cesty/dotazu, sdílený ViewModelIntent extras, Bundle, SharedPreferences
Hluboké odkazyVestavěná podpora navDeepLinkintent-filter v manifestu
Back stackAutomatická správa popBackStackFragmentManager.popBackStack()
Doba přepnutí5–15 ms (v rámci procesu)50–200 ms (s novým vytvořením)

Přechod z Intent na composable() — není jen změna API, ale změna architektonického paradigmatu. Místo explicitního uvádění, která Activity se má otevřít, vývojář deklarativně popisuje všechny možné trasy na jednom místě, což zlepšuje čitelnost kódu a zjednodušuje testování navigace. Podle údajů Google I/O 2024, Jetpack Compose s Navigation Compose snižuje množství kódu pro navigaci o 40–60% ve srovnání s FragmentManager.

Typické chyby s composable()

Jedna z nejčastějších chyb — znovuvytvoření NavController při rekompozici. Pokud je NavController vytvořen přes rememberNavController() na úrovni nadřazeného composable, který se může znovu vytvořit při změně stavu, navigace se rozbije — historie přechodů se ztratí. Správným řešením je zvednout NavController na úroveň stabilního composable, například na úroveň Activity nebo kořenového composable aplikace.

Druhý častý problém — nekonečná rekompozice při navigaci. K tomu dochází, když je volání navController.navigate() umístěno přímo v těle composable funkce. Protože navigace mění stav NavHost, spouští to rekompozici, která znovu volá navigate(), čímž vytváří cyklus. Všechna volání navigace by měla být zabalena do lambda obsluh (onClick, onButtonPressed), nikoli prováděna v kompozici.

Třetí chyba — nesprávná správa back stack při použití BottomNavigation. Jednoduchá navigace přes navigate() při každém přepnutí karty přidává nový záznam do zásobníku, místo aby se vrátila k existujícímu. Pro BottomNavigation je třeba použít navController.navigate() s restoreState = true a launchSingleTop = true, což zajišťuje správné obnovení stavu při přepínání mezi kartami.

kotlin
fun NavController.navigateToTab(route: String) {
    navigate(route) {
        popUpTo(navController.graph.findStartDestination().id) {
            saveState = true
        }
        launchSingleTop = true
        restoreState = true
    }
}

Často kladené otázky

Jaký je rozdíl mezi composable() a běžnou funkcí @Composable?

composable() — není anotace, ale rozšiřující funkce NavHost, která připojuje trasu k UI. Běžná funkce @Composable jednoduše popisuje rozložení, zatímco composable() registruje toto rozložení v navigačním grafu s uvedenou trasou, čímž jej zpřístupňuje pro navigaci přes NavController.

Jak předat složitý objekt mezi composable() obrazovkami?

Doporučuje se předávat pouze identifikátor (ID) přes parametr cesty a samotný objekt načítat na obrazovce podle ID přes repozitář nebo ViewModel. Pokud je přesto nutné objekt předat, použijte NavType.ParcelableType, ale vyhněte se předávání objektů větších než 1 KB — to může vést k TransactionTooLargeException.

Proč se composable() obrazovka znovu vytváří při otočení obrazovky?

Otočení obrazovky způsobuje změnu konfigurace, která ve výchozím nastavení znovu vytváří Activity. Pro zachování stavu composable obrazovek použijte rememberSaveable pro jednoduchá data nebo ViewModel s rozsahem dané obrazovky. Navigation Compose obnoví back stack po znovuvytvoření, ale stav uvnitř composable() funkcí se bez rememberSaveable resetuje.

Lze použít composable() bez NavHost?

Ne, composable() — je rozšiřující funkce NavGraphBuilder, která je dostupná pouze uvnitř bloku NavHost. Pro jednoduché nahrazení části UI bez navigace použijte podmíněné vykreslování (when, if) nebo AnimatedContent. composable() je určen právě pro směrování s podporou back stack a hlubokých odkazů.

Jak rozlišit první přechod od návratu zpět v composable()?

Použijte SavedStateHandle uvnitř ViewModel: při prvním přechodu handle.get("initialized") vrátí null, při návratu — uloženou hodnotu. Alternativně analyzujte aktuální pozici v back stack přes navController.previousBackStackEntry — pokud je null, jedná se o první obrazovku v navigačním zásobníku.

Shrnutí

  • composable() — funkce registrace obrazovky v NavHost, hlavní způsob organizace navigace v Jetpack Compose.
  • Trasy — každá obrazovka je identifikována textem trasy s volitelnými parametry cesty a dotazu.
  • Argumenty — předávají se přes NavArgument s podporou primitivních, Parcelable a Serializable typů.
  • Vnoření — composable() podporuje vnořené NavHost pro organizaci modulární navigace s nezávislými zásobníky.
  • Výkon — líná inicializace obrazovek šetří paměť, doba přepínání mezi obrazovkami je 5–15 ms.
  • Chyby — hlavní problémy: znovuvytvoření NavController, nekonečná rekompozice při volání navigate() v těle composable, nesprávná funkce BottomNavigation.
  • Migrace — přechod z FragmentManager na composable() snižuje objem kódu navigace o 40–60% a eliminuje třídu chyb spojených s životním cyklem Fragment.

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é