composable(): mi ez, NavHost és útválasztás a Jetpack Compose-ban

Szerző: IT Sectr Megjelenés: 2026-06-30 Olvasási idő: 9 perc

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 képernyő regisztrálásának függvénye a Navigation Compose könyvtár NavHost-jában.
  • Útvonal — minden képernyőt egy szöveges útvonal azonosít, amely első argumentumként kerül átadásra.
  • Paraméterek — a composable() támogatja az argumentumokat NavArgument-on keresztül, beleértve a kötelező és opcionális paramétereket.
  • Beágyazás — a beágyazott navigáció támogatott beágyazott NavHost-okkal, külön útvonalgráfokkal.
  • Teljesítmény — a composable() lusta inicializálást használ: a képernyő csak az első átlépéskor jön létre.

Mi az a composable() a NavHost-ban

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.

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() }
            )
        }
    }
}

Hogyan működik a composable(): kulcsok és paraméterek

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.

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)
    }

Argumentumok átadása composable()-en keresztül

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ípusaNavTypePélda az útvonalban
IntNavType.IntType"item/{id}"
StringNavType.StringType"user/{name}"
BooleanNavType.BoolType"filter?enabled={value}"
FloatNavType.FloatType"map/{lat}/{lon}"
LongNavType.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.

kotlin
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)
}

Beágyazott navigáció composable()-el

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.

kotlin
// 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 composable() összehasonlítása az Intent navigációval

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:

  • Sebesség — a composable() milliszekundumok alatt vált képernyőt az Activity újbóli létrehozása nélkül, az Intent az Activity újraindítását igényli.
  • Animációk — a Navigation Compose-ban az átmeneti animációk deklaratív módon, az AnimatedNavHost-on keresztül állíthatók be, overridePendingTransition nélkül.
  • Megosztott állapot — a composable() egy megosztott ViewModel scope-ban működik, ami leegyszerűsíti az adatátvitelt a képernyők között Intent extras nélkül.
Jellemzőcomposable()Intent / Fragment
ArchitektúraSingle Activity, Compose faMulti Activity, Fragment vermek
Adatátvitelelérési út/lekérdezés paraméterek, megosztott ViewModelIntent extras, Bundle, SharedPreferences
Mély linkekBeépített navDeepLink támogatásintent-filter a manifestben
Visszalépési veremAutomatikus popBackStack kezelésFragmentManager.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.

Tipikus hibák a composable()-el

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.

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

Gyakran Ismételt Kérdések

Mi a különbség a composable() és egy szokásos @Composable függvény között?

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.

Hogyan adjunk át összetett objektumot composable() képernyők között?

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.

Miért jön létre újra a composable() képernyő a képernyő elforgatásakor?

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.

Használható a composable() NavHost nélkü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.

Hogyan különböztethető meg az első átlépés a visszatéréstől a composable()-ben?

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

  • composable() — képernyő regisztrációs függvény a NavHost-ban, a navigáció szervezésének fő módja a Jetpack Compose-ban.
  • Útvonalak — minden képernyőt egy útvonal szöveg azonosít opcionális elérési út és lekérdezési paraméterekkel.
  • Argumentumok — NavArgument-en keresztül kerülnek átadásra primitív, Parcelable és Serializable típusok támogatásával.
  • Beágyazás — a composable() támogatja a beágyazott NavHost-okat moduláris navigáció szervezéséhez független vermekkel.
  • Teljesítmény — a képernyők lusta inicializálása memóriát takarít meg, a képernyők közötti váltási idő 5–15 ms.
  • Hibák — fő problémák: NavController újbóli létrehozása, végtelen recompozíció a navigate() hívásakor a composable testében, a BottomNavigation helytelen működése.
  • Migráció — a FragmentManager-ről composable()-re való áttérés 40–60%-kal csökkenti a navigációs kód mennyiségét és kiküszöböli a Fragment életciklusával kapcsolatos hibák osztályát.

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.

Projekt megbeszélése

Olvassa el is