composable() — a Navigation Compose könyvtár függvénye, amely regisztrál egy képernyőt a NavHost-ban és összekapcsolja az URL útvonalat a Compose elrendezéssel. Amikor a navigáció egy megadott útvonalra lép, a Jetpack Compose meghívja a megfelelő composable függvényt és megjeleníti azt aktuális képernyőként. A FragmentManager-től vagy Intent-alapú navigációtól eltérően a composable() egyetlen Activity szintjén működik, és teljesen Kotlin DSL-en keresztül irányítható. A Android Developers (2025) adatai szerint a Jetpack Compose-ra épülő modern Android alkalmazások több mint 73%-a pontosan a Navigation Compose-t használja a képernyőváltások szervezésére.
Főbb pontok
composable() — a NavHost objektum kiterjesztési függvénye (extension function). A Kotlin DSL lehetővé teszi, hogy a NavHost blokkon belül hívja meg az alkalmazás összes képernyőjének deklaratív leírásához. Minden hívás létrehoz egy bejegyzést a navigációs gráfban, összekapcsolva egy szöveges útvonalat egy composable függvénnyel. Amikor a felhasználó egy adott útvonalra navigál, a NavHost megjeleníti a megfelelő composable-t aktuális képernyőként, elrejtve az előzőt.
A Navigation Compose könyvtárat a Google 2021-ben mutatta be a Fragment-alapú navigáció alternatívájaként a Jetpack Compose-hoz. A fő előny — teljes kompatibilitás a Compose paradigmával: a composable() ugyanabban az életciklusban működik, mint a többi Compose komponens, FragmentManager vagy tranzakciók nélkül. Ez kiküszöböli a Fragment és Compose életciklus-eltéréséből adódó hibák osztályát.
Minden composable() fogad egy szöveges útvonalat (route) és egy lambda függvényt, amely egy NavBackStackEntry objektumot kap és visszaad egy Composable UI-t. A lambdán belül a navController híváson keresztül elérhető a NavController a scope-ból, ami lehetővé teszi a más képernyőkre való átlépések szervezését. Ez az architektúra egyértelművé és kiszámíthatóvá teszi a navigációt.
@Composable
fun AppNavigation() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "home"
) {
composable("home") {
HomeScreen(
onNavigateToProfile = {
navController.navigate("profile")
}
)
}
composable("profile") {
ProfileScreen(
onBack = { navController.popBackStack() }
)
}
}
}
Minden composable() hívás létrehoz a NavHost belső gráfjában egy csomópontot egyedi útvonal-azonosítóval. Amikor a NavController végrehajtja a navigate()-et, a könyvtár összehasonlítja a kért útvonalat az összes regisztrált composable csomóponttal, és megtalálja a megfelelőt. Az egyezés után létrejön egy NavBackStackEntry, amely a navigációs verembe kerül, és elindul az UI kompozíció.
A composable() belső implementációja a lusta inicializálás mechanizmusát használja: a képernyő kompozíciója csak az első, erre az útvonalra történő átlépéskor történik meg. Ez azt jelenti, hogy azok a képernyők, amelyekre a felhasználó soha nem navigált, nem foglalnak memóriát és nem hajtanak végre semmilyen kódot. Ez a megközelítés jelentősen javítja a sok képernyővel rendelkező alkalmazások teljesítményét.
A key paraméter a composable()-ben lehetővé teszi a képernyő újbóli létrehozásának kezelését. Alapértelmezés szerint a composable nem jön létre újra ugyanarra az útvonalra történő ismételt átlépéskor — a NavHost a meglévő back stack bejegyzést használja. Ha azonban a key átadásra kerül és megváltozik, a NavHost létrehozza a composable függvény egy új példányát. Ez hasznos dinamikus adatokkal rendelkező képernyőknél, ahol az állapotot kényszeríteni kell az újbóli megnyitáskor.
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() egy rugalmas argumentumrendszert támogat az arguments paraméteren keresztül. Minden argumentumot egy NavArgument objektum ír le, amely meghatározza a típust, az alapértelmezett értéket és a kötelezőséget. Az argumentumok az útvonalban elérési út paraméterként (kapcsos zárójeleken keresztül) vagy lekérdezési paraméterként (kérdőjelen keresztül) kerülnek átadásra.
Az elérési út paraméterek közvetlenül az útvonal sablonjában vannak megadva: "profile/{userId}". A "profile/42" útvonalra való átlépéskor a NavHost automatikusan kinyeri a 42 értéket, és elérhetővé teszi a backStackEntry.arguments-en keresztül. A lekérdezési paraméterek a kérdőjel után kerülnek hozzáadásra: "search?query={text}" és szintén automatikusan elemzésre kerülnek a könyvtár által.
Az argumentumok kinyerésekor fontos ellenőrizni a paraméter kötelezőségét a NavType.isNullableAllowed segítségével, és alapértelmezett értékeket biztosítani a NavArgument defaultValue-n keresztül. Ha egy kötelező paraméter hiányzik, a Navigation Compose IllegalArgumentException kivételt generál, ami megakadályozza a nem észrevehető hibákat a helytelen útvonalakkal.
| Argumentum típusa | NavType | Példa az útvonalban |
|---|---|---|
| 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}" |
Összetett objektumok átadásához ajánlott a NavType.ParcelableType vagy NavType.SerializableType használata. A Google azonban azt tanácsolja, hogy minimalizáljuk az átadott adatok méretét — jobb egy azonosítót átadni, és az objektumot azonosító alapján betölteni a képernyőn belül. Ez megelőzi a nagy szerializált adatokkal kapcsolatos problémákat, és leegyszerűsíti a konfigurációs változások kezelését.
data class Profile(val id: Int, val name: String) : Parcelable
// Navigáljon minimális adatokkal
navController.navigate("profile/42")
// Argumentumok lekérése a képernyőn
composable(
route = "profile/{userId}",
arguments = listOf(
NavArgument("userId") { type = NavType.IntType }
)
) { backStackEntry ->
val userId = backStackEntry.arguments?.getInt("userId") ?: 0
ProfileDetailScreen(userId = userId)
}
A valódi alkalmazásokban gyakran szükséges beágyazott navigációs gráfok szervezése — például külön képernyőverem egy BottomNavigation fülön belül. composable() támogatja a beágyazást a beágyazott NavHost-ok mechanizmusán keresztül: a composable képernyőn belül deklarálható egy saját NavHost független útvonalveremmel.
Minden beágyazott NavHost saját NavController-rel és back stack-kel rendelkezik. Ez azt jelenti, hogy a fülön belüli navigáció nem befolyásolja a navigációt más fülekben — a felhasználó szabadon válthat a fülek között anélkül, hogy elveszítené a navigációs előzményeket mindegyiken belül. Ezt az architektúrát Scoped Navigation-nak hívják, és a Google ajánlja összetett többszintű navigációval rendelkező alkalmazásokhoz.
A beágyazott navigáció implementálásakor fontos a NavController állapotának helyes kezelése: minden beágyazott NavHost-nak tárolnia kell a saját rememberNavController-ját a composable függvény scope-ján belül. A Android Developer Summit 2024 adatai szerint a három vagy több füllel rendelkező Jetpack Compose alkalmazások több mint 40%-a beágyazott NavHost architektúrát használ a modulok közötti navigáció elkülönítésére.
// Fő NavHost fülekkel
composable("tabs") {
MainTabsScreen { tab ->
when (tab) {
Tab.Home -> HomeNavGraph()
Tab.Search -> SearchNavGraph()
}
}
}
// Beágyazott gráf a Home fülben
@Composable
fun HomeNavGraph() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "home_feed"
) {
composable("home_feed") { FeedScreen() }
composable("home_detail/{postId}") { PostDetailScreen() }
}
}
A Jetpack Compose előtt az Android szabványos navigációs módszere az Intent és FragmentManager használata volt. Intent — egy rendszerüzenet, amely elindít egy új Activity-t, ami a teljes View fa újbóli létrehozását jelenti. Ezzel szemben a composable() egyetlen Activity-n belül működik, és egyszerűen lecseréli a Compose fa egy részét, ami jelentősen gyorsabb és memóriahatékonyabb.
A composable() és az Intent-alapú navigáció közötti fő különbségek:
| Jellemző | composable() | Intent / Fragment |
|---|---|---|
| Architektúra | Single Activity, Compose fa | Multi Activity, Fragment vermek |
| Adatátvitel | elérési út/lekérdezés paraméterek, megosztott ViewModel | Intent extras, Bundle, SharedPreferences |
| Mély linkek | Beépített navDeepLink támogatás | intent-filter a manifestben |
| Visszalépési verem | Automatikus popBackStack kezelés | FragmentManager.popBackStack() |
| Váltási idő | 5–15 ms (folyamaton belül) | 50–200 ms (újbóli létrehozással) |
Az Intent-ről composable()-re való áttérés — nem csak API váltás, hanem architekturális paradigmaváltás. Ahelyett, hogy explicit módon megadnánk, melyik Activity-nek kell megnyílnia, a fejlesztő deklaratív módon írja le az összes lehetséges útvonalat egy helyen, ami javítja a kód olvashatóságát és leegyszerűsíti a navigáció tesztelését. A Google I/O 2024 adatai szerint a Jetpack Compose Navigation Compose-zal 40–60%-kal csökkenti a navigációs kód mennyiségét a FragmentManager-hez képest.
Az egyik leggyakoribb hiba — a NavController újbóli létrehozása recompozíciókor. Ha a NavController a rememberNavController()-ön keresztül a szülő composable szintjén jön létre, amely az állapotváltozáskor újból létrehozható, a navigáció megszakad — a navigációs előzmények elvesznek. A helyes megoldás a NavController egy stabil composable szintre emelése, például az Activity vagy az alkalmazás gyökér composable szintjére.
A második gyakori probléma — végtelen recompozíció navigáció közben. Ez akkor történik, amikor a navController.navigate() hívás közvetlenül a composable függvény testében van elhelyezve. Mivel a navigáció megváltoztatja a NavHost állapotát, ez recompozíciót vált ki, amely újra meghívja a navigate()-et, létrehozva egy ciklust. Minden navigációs hívást lambda-kezelőkbe (onClick, onButtonPressed) kell csomagolni, nem a kompozícióban végrehajtani.
A harmadik hiba — a visszalépési verem helytelen kezelése BottomNavigation használatakor. Az egyszerű navigáció a navigate()-en keresztül minden fülváltáskor új bejegyzést ad a veremhez, ahelyett, hogy a meglévőhöz térne vissza. A BottomNavigation esetében a navController.navigate() restoreState = true és launchSingleTop = true paraméterekkel használandó, ami biztosítja az állapot helyes visszaállítását a fülek közötti váltáskor.
fun NavController.navigateToTab(route: String) {
navigate(route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
Gyakran Ismételt Kérdések
composable() — nem annotáció, hanem a NavHost kiterjesztési függvénye, amely egy útvonalat kapcsol az UI-hoz. Egy szokásos @Composable függvény egyszerűen leírja az elrendezést, míg a composable() regisztrálja ezt az elrendezést a navigációs gráfban a megadott útvonallal, elérhetővé téve azt navigáció számára a NavController-en keresztül.
Ajánlott csak azonosítót (ID) átadni az elérési út paraméteren keresztül, és magát az objektumot a képernyőn betölteni ID alapján egy repository vagy ViewModel segítségével. Ha az objektumot mégis át kell adni, használja a NavType.ParcelableType-ot, de kerülje az 1 KB-nál nagyobb objektumok átadását — ez TransactionTooLargeException kivételhez vezethet.
A képernyő elforgatása konfigurációváltozást okoz, amely alapértelmezés szerint újból létrehozza az Activity-t. A composable képernyők állapotának megőrzéséhez használja a rememberSaveable-t egyszerű adatokhoz vagy ViewModel-t az adott képernyő scope-jával. A Navigation Compose visszaállítja a back stack-et az újbóli létrehozás után, de a composable() függvényeken belüli állapot rememberSaveable nélkül visszaállításra kerül.
Nem, a composable() — a NavGraphBuilder kiterjesztési függvénye, amely csak a NavHost blokkon belül érhető el. Egyszerű UI rész lecseréléséhez navigáció nélkül használjon feltételes megjelenítést (when, if) vagy AnimatedContent-ot. A composable() pontosan a back stack és mély linkek támogatásával rendelkező útválasztásra tervezték.
Használja a SavedStateHandle-t a ViewModel-en belül: az első átlépéskor a handle.get("initialized") null-t ad vissza, visszatéréskor — a mentett értéket. Alternatívaként elemezze az aktuális pozíciót a back stack-ben a navController.previousBackStackEntry segítségével — ha null, ez az első képernyő a navigációs veremben.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is