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() — 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.
@Composable
fun AppNavigation() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "home"
) {
composable("home") {
HomeScreen(
onNavigateToProfile = {
navController.navigate("profile")
}
)
}
composable("profile") {
ProfileScreen(
onBack = { navController.popBackStack() }
)
}
}
}
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í.
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)
}
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 argumentu | NavType | Příklad v trase |
|---|---|---|
| Int | NavType.IntType | "item/{id}" |
| String | NavType.StringType | "user/{name}" |
| Boolean | NavType.BoolType | "filter?enabled={value}" |
| Float | NavType.FloatType | "map/{lat}/{lon}" |
| Long | NavType.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.
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)
}
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.
// 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() }
}
}
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:
| Vlastnost | composable() | Intent / Fragment |
|---|---|---|
| Architektura | Single Activity, Compose strom | Multi Activity, Fragment zásobníky |
| Přenos dat | parametry cesty/dotazu, sdílený ViewModel | Intent extras, Bundle, SharedPreferences |
| Hluboké odkazy | Vestavěná podpora navDeepLink | intent-filter v manifestu |
| Back stack | Automatická správa popBackStack | FragmentManager.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.
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.
fun NavController.navigateToTab(route: String) {
navigate(route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
Často kladené otázky
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.
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.
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.
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ů.
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í
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í.
Přečtěte si také