NavHost ist ein composable-Container, der als Einstiegspunkt für den Navigationsgraphen in Jetpack Compose dient. Er verbindet einen NavController mit einer Reihe von Routen und rendert den aktuellen Bildschirm basierend auf dem Zustand des Back-Stacks. Laut Android Developers (2025) ist NavHost eine obligatorische Komponente für jede Compose-App mit Navigation. Innerhalb von NavHost werden composable-Routen mit optionalen Argumenten, Deep Links und Animationen registriert. Jede Route ist eine normale composable-Funktion, die einen NavBackStackEntry mit Übergangsdaten erhält. NavHost verarbeitet automatisch den Zurück-Button, das Speichern des Zustands und die Wiederherstellung bei Rekonfiguration.
Wichtige Punkte
NavHost ist eine composable-Funktion, die einen Container zum Anzeigen des aktuellen Navigationsbildschirms bereitstellt. NavHost nimmt einen NavController, startDestination und einen über Kotlin DSL erstellten Routengraphen entgegen. Wenn sich die aktuelle Route ändert, wechselt NavHost das angezeigte composable mit der angegebenen Animation.
NavHost fungiert als Bildschirmwechsler: er verfolgt den aktuellen NavBackStackEntry vom NavController und rendert den entsprechenden composable-Block. Jeder Bildschirm ist eine unabhängige composable-Funktion, die einen NavBackStackEntry mit Routenargumenten erhält. Alle Bildschirme existieren in einem einzigen Kompositionsbaum, aber NavHost zeigt jeweils nur einen an und blendet die anderen durch Animation aus.
Im Gegensatz zu FragmentManager erstellt NavHost keinen Fragment für jeden Bildschirm. Der gesamte Lebenszyklus wird über CompositionLifecycle verwaltet — composable-Funktionen haben kein onStart/onResume, daher werden LaunchedEffect und DisposableEffect für Seiteneffekte verwendet. NavHost abonniert automatisch den NavController und setzt die UI neu zusammen, wenn sich die Route ändert.
Laut Google ist NavHost seit Navigation 2.4.0 eine stabile API. Ab 2.8.0 unterstützt NavHost typsichere Navigation über Kotlin Serialization und ersetzt String-Routen durch Datenklassen. NavHost unterstützt auch verschachtelte Graphen, was eine modulbasierte Navigationsorganisation ermöglicht.
NavHost wird mit zwei erforderlichen Parametern erstellt: navController (eine Instanz von NavHostController) und startDestination (der Routen-String des ersten Bildschirms). Der dritte Parameter ist ein Builder-Block, in dem alle Routen über composable(), navigation() und dialog() registriert werden.
@Composable
fun AppNavHost(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = "home"
) {
composable("home") { HomeScreen(navController) }
composable("settings") { SettingsScreen(navController) }
}
}
startDestination ist die Route, die beim ersten Start von NavHost geöffnet wird. Wenn der Back-Stack leer ist, fügt NavHost automatisch startDestination zum Stack hinzu. Bei Rekonfiguration (Bildschirmdrehung) stellt NavHost die letzte Route aus savedState wieder her, nicht startDestination.
Für BottomNavigation ist startDestination eine der Routen des unteren Panels. Die verbleibenden Panel-Routen werden als separate composable-Einträge hinzugefügt. NavHost sollte innerhalb von Scaffold.content platziert werden — wo der Hauptinhalt der App angezeigt wird. NavHost belegt die gesamte verfügbare Höhe abzüglich TopAppBar und BottomNavigation.
Die Funktion composable(route, arguments, deepLinks, enterTransition, exitTransition, content) registriert eine Route im NavHost-Graphen. Der Parameter route ist ein String, der den Pfad mit optionalen Platzhaltern in der Form {paramName} beschreibt. Der Platzhalter wird während der Navigation durch einen tatsächlichen Wert ersetzt.
Der content-Block von composable erhält einen NavBackStackEntry, aus dem die Argumente extrahiert werden. Die Bildschirm-composable-Funktion wird nur gerendert, wenn die aktuelle NavController-Route mit der Route übereinstimmt. Bei Nichtübereinstimmung wird das composable aus der Komposition entfernt, aber sein Zustand kann über rememberSaveable oder ViewModel mit SavedStateHandle erhalten bleiben.
composable(
route = "article/{articleId}",
arguments = listOf(navArgument("articleId") {
type = NavType.IntType
defaultValue = 0
}),
deepLinks = listOf(navDeepLink { uriPattern = "https://app.example/article/{articleId}" })
) { backStackEntry ->
val articleId = backStackEntry.arguments?.getInt("articleId") ?: 0
ArticleScreen(articleId = articleId)
}
Die Anzahl der composable-Einträge innerhalb von NavHost kann von wenigen bis zu Hunderten reichen. Für große Anwendungen werden Routen über Module aufgeteilt und über verschachtelte Graphen verbunden. Jedes composable kann eigene Animationseinstellungen, Deep Links und Argumente haben.
Routenargumente werden über den Parameter arguments: List<NamedNavArgument> in composable() definiert. Jedes Argument wird über navArgument(name) { type; defaultValue } definiert. NavType bestimmt den Argumenttyp: StringType, IntType, LongType, FloatType, BoolType, ParcelableType und ReferenceType.
| Routenparameter | Beispielroute | NavType |
|---|---|---|
| Pfad (path) | "user/{id}" | NavType.IntType |
| Abfrage (query) | "search?q={query}" | NavType.StringType |
| Optional | "details/{id}?tab={tab}" | StringType + defaultValue="" |
| Parcelable | "checkout/{order}" | NavType.ParcelableType |
Argumente werden aus NavBackStackEntry über arguments?.getInt("id") extrahiert. Für erforderliche Argumente kann defaultValue weggelassen werden — NavType verwendet null. Für optionale Argumente muss defaultValue gesetzt werden, sonst wirft die Navigation eine Ausnahme, wenn der Parameter fehlt.
Seit Navigation 2.8.0 wird typsichere Navigation empfohlen: Definieren Sie eine versiegelte Klasse oder Datenklasse für Routen mit Kotlin Serialization. Verwenden Sie anstelle einer String-Route composable<RouteType> { backStackEntry -> }. Dies eliminiert Tippfehler in Routen und generiert automatisch NavType für Argumente. Zur Migration fügen Sie die Abhängigkeit navigation-compose-typesafe und das Kotlin Serialization Plugin hinzu.
nested graphs — ein Mechanismus zum Gruppieren von Routen innerhalb von NavHost mit der Funktion navigation(route, startDestination). Ein verschachtelter Graph hat ein eigenes Routenpräfix und startDestination, und alle seine Routen sind über das Präfix zugänglich. Verschachtelte Graphen werden für modulare Architekturen verwendet, bei denen jedes Feature-Modul seinen eigenen Untergraphen registriert.
Vorteile verschachtelter Graphen: Routenisolierung innerhalb eines Moduls, ein einheitlicher Back-Stack für eine Gruppe von Bildschirmen und die Möglichkeit, über Präfix zu navigieren, ohne die interne Struktur offenzulegen. Beispielsweise enthält der Graph „aauth“ „aauth/login“ und „aauth/register“. Die Navigation ist entweder über die vollständige Route oder über Präfix mit Weiterleitung zu startDestination möglich.
NavHost(navController = navController, startDestination = "main") {
composable("main") { MainScreen(navController) }
navigation(
route = "auth",
startDestination = "auth/login"
) {
composable("auth/login") { LoginScreen(navController) }
composable("auth/register") { RegisterScreen(navController) }
}
}
Verschachtelte Graphen unterstützen die Argumentübergabe auf Graphenebene: Im Routenpräfix deklarierte Parameter werden an alle internen Routen weitergegeben. Zum Löschen eines verschachtelten Graphen verwenden Sie popBackStack(route) — es entfernt alle internen Einträge. Verschachtelte Graphen haben keine Tiefenbeschränkung, aber für die Lesbarkeit werden nicht mehr als 3 Ebenen empfohlen.
NavHost unterstützt Übergangsanimationen zwischen composable-Routen über die Parameter enterTransition, exitTransition, popEnterTransition und popExitTransition. Animationen werden einmal für NavHost festgelegt und gelten für alle Routen, oder einzeln für jedes composable. Standardmäßig sind Animationen deaktiviert.
Typische Konfiguration: enterTransition = slideInHorizontally(initialOffsetX = { it }) — der Bildschirm gleitet von rechts herein; exitTransition = slideOutHorizontally(targetOffsetX = { -it }) — der Bildschirm gleitet nach links hinaus. Für die Pop-Animation sind die Richtungen gespiegelt: Der Bildschirm gleitet von links herein und nach rechts hinaus. Für BottomNavigation wird fadeIn/fadeOut ohne Gleiten verwendet.
NavHost(
navController = navController,
startDestination = "home",
enterTransition = { slideInHorizontally(initialOffsetX = { it }) + fadeIn() },
exitTransition = { slideOutHorizontally(targetOffsetX = { -it }) + fadeOut() },
popEnterTransition = { slideInHorizontally(initialOffsetX = { -it }) + fadeIn() },
popExitTransition = { slideOutHorizontally(targetOffsetX = { it }) + fadeOut() }
) { /* composable routes */ }
Benutzerdefinierte Animationen werden mit der Compose Animation API erstellt: AnimatedContentTransitionScope bietet Zugriff auf Containerabmessungen, Animationsfortschritt und Richtung. Für Shared-Element-Übergänge (ein Element bewegt sich nahtlos zu einem anderen Bildschirm) wird die Bibliothek Accompanist Navigation Animation oder eine benutzerdefinierte Implementierung über sharedElement Modifier benötigt. Laut Android Developers (2025) wird die Standard-Slide-Animation (Eingang von rechts, Ausgang nach links) in 80% der Android-Apps mit Navigation verwendet.
Häufig gestellte Fragen
Technisch ja, aber es wird nicht empfohlen. Jeder NavHost erstellt einen unabhängigen Back-Stack, was die einheitliche Navigation beeinträchtigt. Die Ausnahme sind getrennte Bereiche, wie ein NavHost für den Hauptinhalt und ein NavHost für ein BottomSheet mit eigener Navigation.
NavHost ist ein Navigationscontainer, der Bildschirme wechselt. Scaffold ist das Layout der gesamten Seite (TopAppBar, BottomNavigation, FloatingActionButton). Normalerweise wird NavHost innerhalb von Scaffold.content platziert. Scaffold verwaltet keine Navigation, sondern stellt nur Slots für UI-Komponenten bereit.
Ein ViewModel wird innerhalb eines NavBackStackEntry über viewModel() erstellt. Um ein ViewModel zwischen Bildschirmen zu teilen, verwenden Sie parentNavController: Binden Sie das gemeinsame ViewModel an den übergeordneten Eintrag. Eine Alternative ist DI (Hilt/Koin) mit NavGraph-Scope.
Dies ist normales Verhalten — NavHost entfernt das composable aus der Komposition beim Verlassen einer Route. Um den Zustand zu erhalten, verwenden Sie rememberSaveable für den UI-Zustand und ViewModel mit SavedStateHandle für die Geschäftslogik.
Fügen Sie eine letzte Route composable("404") hinzu und navigieren Sie zu ihr, wenn ein unbekannter Deep Link empfangen wird. NavHost hat keine Catch-All-Route — überprüfen Sie die Route im Deep-Link-Intent-Handler vor navigate(). Wenn die Route nicht gefunden wird, navigieren Sie zu 404.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch