composable() — är en funktion i Navigation Compose-biblioteket som registrerar en skärm i NavHost och kopplar en URL-rutt till Compose-layouten. När navigeringen går till en angiven rutt anropar Jetpack Compose motsvarande composable-funktion och visar den som den aktuella skärmen. Till skillnad från FragmentManager eller Intent-baserad navigering fungerar composable() på nivån av en enda Activity och hanteras helt via Kotlin DSL. Enligt data från Android Developers (2025) använder mer än 73% av moderna Android-applikationer byggda på Jetpack Compose just Navigation Compose för att organisera skärmbyten.
Huvudpunkter
composable() — är en tilläggsfunktion (extension function) för NavHost-objektet. Kotlin DSL gör det möjligt att anropa den inuti NavHost-blocket för att deklarativt beskriva alla skärmar i applikationen. Varje anrop skapar en post i navigeringsdiagrammet och kopplar en textrutt till en composable-funktion. När användaren navigerar till en specifik rutt visar NavHost motsvarande composable som den aktuella skärmen och döljer den föregående.
Navigation Compose-biblioteket introducerades av Google 2021 som ett alternativ till Fragment-baserad navigering för Jetpack Compose. Den främsta fördelen — full kompatibilitet med Compose-paradigmet: composable() fungerar i samma livscykel som andra Compose-komponenter, utan behov av FragmentManager eller transaktioner. Detta eliminerar en klass av fel relaterade till bristande överensstämmelse mellan Fragment och Compose-livscykler.
Varje composable() tar emot en textrutt (route) och en lambdafunktion som får ett NavBackStackEntry-objekt och returnerar ett Composable UI. Inuti lambdan kan NavController nås via anropet navController från scopet, vilket gör det möjligt att organisera övergångar till andra skärmar. Denna arkitektur gör navigeringen explicit och förutsägbar.
@Composable
fun AppNavigation() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "home"
) {
composable("home") {
HomeScreen(
onNavigateToProfile = {
navController.navigate("profile")
}
)
}
composable("profile") {
ProfileScreen(
onBack = { navController.popBackStack() }
)
}
}
}
Varje composable()-anrop skapar i NavHosts interna diagram en nod med en unik ruttidentifierare. När NavController utför navigate() jämför biblioteket den begärda rutten med alla registrerade composable-noder och hittar den matchande. Efter matchning skapas en NavBackStackEntry som placeras på navigeringsstacken och UI-kompositionen startar.
Den interna implementeringen av composable() använder lat initialisering: kompositionen av skärmen sker endast vid den första övergången till denna rutt. Detta innebär att skärmar som användaren aldrig har navigerat till inte upptar minne och inte exekverar någon kod. Detta tillvägagångssätt förbättrar avsevärt prestandan för applikationer med ett stort antal skärmar.
Parametern key i composable() gör det möjligt att hantera återskapande av skärmen. Som standard återskapas composable inte vid en upprepad övergång till samma rutt — NavHost använder den befintliga back stack-posten. Men om key skickas och ändras, skapar NavHost en ny instans av composable-funktionen. Detta är användbart för skärmar med dynamisk data där tillståndet måste uppdateras tvångsmässigt vid återöppning.
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() stöder ett flexibelt argumentsystem via parametern arguments. Varje argument beskrivs av ett NavArgument-objekt som definierar typ, standardvärde och obligatoriskhet. Argument skickas i rutten som sökvägsparametrar (via klammerparenteser) eller frågeparametrar (via frågetecken).
Sökvägsparametrar anges direkt i ruttmallen: "profile/{userId}". Vid navigering till rutten "profile/42" extraherar NavHost automatiskt värdet 42 och gör det tillgängligt via backStackEntry.arguments. Frågeparametrar läggs till efter frågetecknet: "search?query={text}" och tolkas också automatiskt av biblioteket.
Vid extrahering av argument är det viktigt att kontrollera parameterns obligatoriskhet via NavType.isNullableAllowed och tillhandahålla standardvärden via NavArgument defaultValue. Om en obligatorisk parameter saknas genererar Navigation Compose ett IllegalArgumentException-undantag, vilket förhindrar osynliga buggar med felaktiga rutter.
| Argumenttyp | NavType | Exempel i rutt |
|---|---|---|
| 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}" |
För överföring av komplexa objekt rekommenderas att använda NavType.ParcelableType eller NavType.SerializableType. Google rekommenderar dock att minimera storleken på överförda data — det är bättre att skicka en identifierare och ladda objektet via ID inuti skärmen. Detta förhindrar problem med stora serialiserade data och förenklar hanteringen av konfigurationsändringar.
data class Profile(val id: Int, val name: String) : Parcelable
// Navigera med minimal data
navController.navigate("profile/42")
// Hämta argument på skärmen
composable(
route = "profile/{userId}",
arguments = listOf(
NavArgument("userId") { type = NavType.IntType }
)
) { backStackEntry ->
val userId = backStackEntry.arguments?.getInt("userId") ?: 0
ProfileDetailScreen(userId = userId)
}
I verkliga applikationer krävs ofta organisering av nästlade navigeringsdiagram — till exempel en separat stack av skärmar inuti en flik i BottomNavigation. composable() stöder nästling via mekanismen med nästlade NavHost: inuti en composable-skärm kan en egen NavHost med en oberoende ruttstack deklareras.
Varje nästlad NavHost har sin egen NavController och back stack. Detta innebär att navigering inuti en flik inte påverkar navigeringen i andra flikar — användaren kan fritt växla mellan flikar utan att förlora navigeringshistoriken inom varje flik. Denna arkitektur kallas Scoped Navigation och rekommenderas av Google för applikationer med komplex flernivånavigering.
Vid implementering av nästlad navigering är det viktigt att hantera NavController-statusen korrekt: varje nästlad NavHost bör lagra sin egen rememberNavController inom scopet av composable-funktionen. Enligt data från Android Developer Summit 2024 använder mer än 40% av Jetpack Compose-applikationer med tre eller fler flikar arkitekturen med nästlade NavHost för isolering av navigering mellan moduler.
// Huvud-NavHost med flikar
composable("tabs") {
MainTabsScreen { tab ->
when (tab) {
Tab.Home -> HomeNavGraph()
Tab.Search -> SearchNavGraph()
}
}
}
// Nästlat diagram i Home-fliken
@Composable
fun HomeNavGraph() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "home_feed"
) {
composable("home_feed") { FeedScreen() }
composable("home_detail/{postId}") { PostDetailScreen() }
}
}
Före Jetpack Compose använde standardmetoden för navigering i Android Intent och FragmentManager. Intent — är ett systemmeddelande som startar en ny Activity, vilket innebär återskapande av hela View-trädet. Till skillnad från detta fungerar composable() inuti en enda Activity och ersätter helt enkelt en del av Compose-trädet, vilket är betydligt snabbare och mer minneseffektivt.
Huvudskillnader mellan composable() och Intent-baserad navigering:
| Egenskap | composable() | Intent / Fragment |
|---|---|---|
| Arkitektur | Single Activity, Compose-träd | Multi Activity, Fragment-stackar |
| Dataöverföring | sökväg/frågeparametrar, delad ViewModel | Intent extras, Bundle, SharedPreferences |
| Djupa länkar | Inbyggt stöd för navDeepLink | intent-filter i manifest |
| Back stack | Automatisk hantering av popBackStack | FragmentManager.popBackStack() |
| Växlingstid | 5–15 ms (inom processen) | 50–200 ms (med återskapande) |
Övergången från Intent till composable() — är inte bara en API-förändring, utan en förändring av arkitekturparadigm. Istället för att explicit ange vilken Activity som ska öppnas, beskriver utvecklaren deklarativt alla möjliga rutter på ett ställe, vilket förbättrar kodläsbarheten och förenklar testning av navigering. Enligt data från Google I/O 2024 minskar Jetpack Compose med Navigation Compose mängden navigeringskod med 40–60% jämfört med FragmentManager.
Ett av de vanligaste felen — återskapande av NavController vid recomposition. Om NavController skapas via rememberNavController() på nivån av den överordnade composable som kan återskapas vid statusändring, bryts navigeringen — navigeringshistoriken går förlorad. Den korrekta lösningen är att lyfta NavController till en stabil composable-nivå, till exempel till Activity-nivån eller applikationens rot-composable.
Det andra vanliga problemet — oändlig recomposition under navigering. Detta inträffar när anropet navController.navigate() placeras direkt i kroppen av composable-funktionen. Eftersom navigering ändrar NavHost-status, utlöser detta en recomposition som återigen anropar navigate(), vilket skapar en cykel. Alla navigeringsanrop bör vara inslagna i lambda-handlers (onClick, onButtonPressed) och inte utföras i kompositionen.
Det tredje felet — felaktig hantering av back stack vid användning av BottomNavigation. Enkel navigering via navigate() vid varje flikväxling lägger till en ny post i stacken istället för att återgå till den befintliga. För BottomNavigation bör navController.navigate() med restoreState = true och launchSingleTop = true användas, vilket säkerställer korrekt återställning av status vid växling mellan flikar.
fun NavController.navigateToTab(route: String) {
navigate(route) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
Vanliga frågor
composable() — är inte en annotering, utan en tilläggsfunktion för NavHost som kopplar en rutt till UI. En vanlig @Composable-funktion beskriver helt enkelt layouten, medan composable() registrerar denna layout i navigeringsdiagrammet med den angivna rutten, vilket gör den tillgänglig för navigering via NavController.
Det rekommenderas att endast skicka en identifierare (ID) via en sökvägsparameter och ladda själva objektet på skärmen via ID från ett repository eller ViewModel. Om objektet ändå måste skickas, använd NavType.ParcelableType, men undvik att skicka objekt större än 1 KB — detta kan leda till TransactionTooLargeException.
Skärmrotation orsakar en konfigurationsändring som som standard återskapar Activity. För att bevara statusen för composable-skärmar, använd rememberSaveable för enkel data eller ViewModel med scopet för den aktuella skärmen. Navigation Compose återställer back stack efter återskapande, men statusen inuti composable()-funktioner återställs utan rememberSaveable.
Nej, composable() — är en tilläggsfunktion för NavGraphBuilder som endast är tillgänglig inuti ett NavHost-block. För enkel ersättning av en UI-del utan navigering, använd villkorlig rendering (when, if) eller AnimatedContent. composable() är avsedd just för routing med stöd för back stack och djupa länkar.
Använd SavedStateHandle inuti ViewModel: vid den första övergången returnerar handle.get("initialized") null, vid återvändo — det sparade värdet. Alternativt, analysera den aktuella positionen i back stack via navController.previousBackStackEntry — om den är null är detta den första skärmen i navigeringsstacken.
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å