NavController är den centrala komponenten i biblioteket Navigation Compose som hanterar navigeringsstacken och back stack-statusen i Android-applikationer. Via NavController utförs övergångar mellan skärmar, återgång till föregående sidor och dataöverföring mellan rutter. Enligt Android Developers (2025) är NavController ett obligatoriskt element i varje Compose-applikation med mer än en skärm. Kontrollenheten skapas via rememberNavController(), skickas till NavHost och är tillgänglig för att anropa navigate() från valfri punkt i kompositionen. Inbyggt stöd för SavedStateHandle sparar automatiskt ViewModel-status vid omkonfigurering.
Huvudpunkter
NavController — är en klass från biblioteket Navigation Compose som implementerar navigeringskontrollenheten för Compose-applikationer. NavController hanterar stacken NavBackStackEntry, där varje post innehåller rutt, argument och skärmstatus. Kontrollenheten stöder grundläggande navigeringsoperationer: övergång, återgång, ersättning och rensning.
Till skillnad från View-systemet, där navigering skedde via FragmentManager eller Intent, fungerar NavController uteslutande i Compose-kontexten. Back stack lagras som en NavDestination-graf, inte som en Fragment-stack. Detta eliminerar overhead för att skapa och förstöra Fragment och förenklar testning — NavController kan mockas via TestNavHostController.
NavController är nära kopplad till NavHost — behållaren som renderar den aktuella skärmen från grafen. Utan NavHost kan NavController inte visa composable-funktioner, men behåller förmågan att hantera stacken. I typisk arkitektur skapas NavController på Activity-nivå eller huvud-composable och skickas nedåt i kompositionsträdet via parametrar.
Enligt Google har NavController genomgått flera stora releaser. Version 2.8.0 lade till Type-Safe Navigation, version 2.9.0 — stöd för predictive back gesture (Android 14+). Kontrollenheten är kompatibel med Material3 Scaffold och BottomNavigation. För multimodulprojekt skickas NavController via DI (Hilt/Koin) eller konstruktorparametrar.
NavController skapas via composable-funktionen rememberNavController(). Funktionen returnerar en NavHostController-instans (arvinge till NavController) bunden till den aktuella composable-ens livscykel. När kompositionen lämnas rensas kontrollenheten. För att spara kontrollenheten vid omkonfigurering, använd rememberSaveable eller ViewModel.
@Composable
fun MyApp() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "main"
) {
composable("main") { MainScreen(navController) }
composable("details") { DetailsScreen(navController) }
}
}
Konfigurationen av NavController omfattar: NavHostController (huvud), TestNavHostController (testning) och ScopedNavController (underordnad för nästlade grafer). För BottomNavigation ska NavController vara unik för hela applikationen — att skapa en ny kontrollenhet i varje flik leder till förlust av stacken. För att skicka kontrollenheten till nästlade skärmar, använd funktionsparametern, inte CompositionLocalProvider, för att behålla läsbarheten.
För att testa navigering, använd TestNavHostController med compose-test-rule. Kontrollenheten gör det möjligt att ställa in den initiala rutten och verifiera att navigate() anropar den förväntade övergången. Testning av NavController kräver ingen emulator — den fungerar med Semantics-matcher i Compose Test.
Metoden navigate(route: String) — det primära sättet för navigering i NavController. Accepterar en ruttsträng, valfria NavOptions och Navigator.Extras. NavOptions hanterar övergångsbeteendet: launchSingleTop (duplicera inte rutten i stacken), popUpTo (rensa stacken till rutten), restoreState (återställ tidigare status).
NavOptions ställs in via builder-syntax: NavOptionsBuilder. Huvudparametrar: popUpTo (route + inclusive/saveState), launchSingleTop (Boolean, true — skapa inte dubblett), restoreState (återställ status vid återgång). Utan popUpTo lägger varje navigate() till en post i stacken, vilket leder till ackumulering av back stack och felaktigt beteende hos Back-knappen.
navController.navigate("profile/42") {
popUpTo("main") { saveState = true }
launchSingleTop = true
restoreState = true
}
Navigator.Extras gör det möjligt att skicka ytterligare data som inte är en del av rutten: shared element för animation, Intent-flaggor, Pac-Man bundle. Extras används sällan — främst för integration med Accompanist Animation eller anpassad Navigator. För de flesta scenarier räcker ruttsträngen och NavOptions.
popBackStack() — metod för återgång till föregående skärm. Utan argument tar den bort den översta stackposten och returnerar true om borttagningen lyckades. Om stacken är tom — returnerar metoden false och Activity stängs (liknande super.onBackPressed()).
Den överlagrade versionen popBackStack(route: String, inclusive: Boolean) tar bort alla poster fram till den angivna rutten. Om inclusive = true — tas den angivna rutten själv också bort. Metoden returnerar Boolean — true om poster hittades och togs bort. Versionen med inclusive är användbar för scenarier med „utgång till huvudskärmen” efter auktorisering eller slutförande av beställning.
| Metod | Beskrivning | Exempel |
|---|---|---|
| popBackStack() | Återgå en skärm bakåt | navController.popBackStack() |
| popBackStack(route, false) | Rensa till rutt (rutten finns kvar) | popBackStack("home", false) |
| popBackStack(route, true) | Rensa till och med rutt | popBackStack("home", true) |
| navigate(route) { popUpTo(route) { inclusive = true } } | Övergång med fullständig rensning | navigate("login") { popUpTo(0) { inclusive = true } } |
För hantering av systemets Back-knapp (hardware back button), använd BackHandler från Compose. BackHandler accepterar enabled och onBack — callback som anropas vid tryckning. För Android 14+ används PredictiveBackGesture, integrerad via NavController från version 2.9.0. Predictive back lägger till en förhandsgranskningsanimation av återgången.
SavedStateHandle — är en mekanism för att spara ViewModel-status vid navigering och omkonfigurering. NavController tillhandahåller automatiskt SavedStateHandle för varje NavBackStackEntry. Via SavedStateHandle lagrar ViewModel skärmstatusen och återställer den vid återgång (restoreState = true).
I Navigation Compose används SavedStateHandle tillsammans med ViewModel: ViewModel initieras via SavedStateHandle som skickas från backStackEntry. Vid övergång till en annan skärm och återgång (med restoreState) får ViewModel den sparade statusen, skapas inte på nytt. Detta är kritiskt för skärmar med datainmatning, filter eller rullning.
class ProfileViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val userId: String = savedStateHandle.get<String>("userId") ?: ""
var searchQuery by savedStateHandle.getStateFlow("search", "")
.collectAsState()
}
SavedStateHandle stöder primitiva typer, String, Bundle och Parcelable. För komplexa objekt, spara endast ID och ladda fullständiga data från förvaringsplatsen. Gränsen för SavedStateHandle är cirka 1 MB, överskridande orsakar TransactionTooLargeException. För stora volymer, använd Room eller DataStore istället för att spara i handle.
Viktigt: SavedStateHandle sparar status endast när restoreState = true används i NavOptions. Om restoreState inte anges, skapas ViewModel på nytt med standardvärden vid återgång. För växling av BottomNavigation med restoreState, sparar NavController statusen för varje flik och återställer den vid upprepat val.
currentBackStackEntryAsState() — funktion som returnerar State<NavBackStackEntry?>, som uppdateras vid varje ändring av den aktuella rutten. Detta är den primära mekanismen för UI-synkronisering med navigering: BottomNavigation markerar det aktiva elementet, Toolbar uppdaterar titeln, Drawer stängs vid övergång.
Funktionen fungerar via snapshotFlow och collectAsState: när back stack ändras, omkomponerar Compose de prenumererade elementen. Viktigt: currentBackStackEntryAsState() uppdateras först efter att övergångsanimationen slutförts. För omedelbar uppdatering, använd currentDestination, som ändras synkront med navigate(), men stöder inte status.
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
Text(
text = when (currentRoute) {
"home" -> "Home"
"profile" -> "Profile"
else -> ""
}
)
För åtkomst till argumenten för den aktuella rutten, använd navBackStackEntry?.arguments. Detta är praktiskt i BottomNavigation: selectedItem beräknas baserat på currentRoute. För felsökning av navigering, använd NavController.addOnDestinationChangedListener(), som loggar varje övergång. I produktion, undvik prenumerationer inom ett stort antal composable — skapa en enda källa i ViewModel och skicka State till UI.
Vanliga frågor
Tekniskt ja, men det rekommenderas inte. En enda NavController säkerställer en konsekvent back stack och förenklar felsökning. Flera kontrollenheter är bara motiverade för nästlade grafer med separat navigering (t.ex. modal bottom sheet med egen stack).
Skicka NavController till ViewModel via konstruktor eller DI. Det är dock bättre att endast skicka callback-funktioner (onNavigate, onBack), inte själva NavController — detta förenklar testning. För händelser, använd Channel<NavEvent> i ViewModel och samla in i UI.
Problemet ligger i livscykeln: om NavController ännu inte är initierad (NavHost är inte byggd), ignoreras navigate(). Använd LaunchedEffect för att anropa navigering efter datainläsning, inte inuti en coroutine med en godtycklig lifecycle.
Anropa navController.navigate("target") { popUpTo(0) { inclusive = true } }. Parametern popUpTo(0) rensar stacken helt, inclusive = true tar bort även den initiala posten. Flaggan launchSingleTop = true förhindrar duplicering av den nya rutten.
NavHostController — en arvinge till NavController med ytterligare metoder för NavHost (t.ex. setOnBackStackChangedListener). NavController — basklassen som kan användas utanför NavHost för programmatisk stackhantering. I de flesta fall används NavHostController.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också