composable(): vad är det, NavHost och routing i Jetpack Compose

Författare: IT Sectr Publicerad: 2026-06-30 Lästid: 9 min

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() — funktion för skärmregistrering i NavHost i Navigation Compose-biblioteket.
  • Rutt — varje skärm identifieras av en textrutt som skickas som första argument.
  • Parametrar — composable() stöder argument via NavArgument, inklusive obligatoriska och valfria.
  • Nästling — nästlad navigering stöds via nästlade NavHost med separata ruttdiagram.
  • Prestanda — composable() använder lat initialisering: skärmen skapas endast vid första övergången.

Vad är composable() i NavHost

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.

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

Hur fungerar composable(): nycklar och parametrar

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.

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

Överföring av argument via composable()

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.

ArgumenttypNavTypeExempel i rutt
IntNavType.IntType"item/{id}"
StringNavType.StringType"user/{name}"
BooleanNavType.BoolType"filter?enabled={value}"
FloatNavType.FloatType"map/{lat}/{lon}"
LongNavType.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.

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

Nästlad navigering med composable()

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.

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

Jämförelse av composable() med Intent-navigering

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:

  • Hastighet — composable() växlar skärmar på millisekunder utan att återskapa Activity, Intent kräver omstart av Activity.
  • Animationer — i Navigation Compose ställs övergångsanimationer in deklarativt via AnimatedNavHost, utan behov av overridePendingTransition.
  • Delad status — composable() fungerar i ett delat ViewModel-scope, vilket förenklar dataöverföring mellan skärmar utan Intent extras.
Egenskapcomposable()Intent / Fragment
ArkitekturSingle Activity, Compose-trädMulti Activity, Fragment-stackar
Dataöverföringsökväg/frågeparametrar, delad ViewModelIntent extras, Bundle, SharedPreferences
Djupa länkarInbyggt stöd för navDeepLinkintent-filter i manifest
Back stackAutomatisk hantering av popBackStackFragmentManager.popBackStack()
Växlingstid5–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.

Vanliga fel med composable()

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.

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

Vanliga frågor

Vad är skillnaden mellan composable() och en vanlig @Composable-funktion?

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.

Hur skickar man ett komplext objekt mellan composable()-skärmar?

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.

Varför återskapas composable()-skärmen vid skärmrotation?

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.

Kan composable() användas utan NavHost?

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.

Hur skiljer man första övergången från återvändo i composable()?

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

  • composable() — funktion för skärmregistrering i NavHost, det huvudsakliga sättet att organisera navigering i Jetpack Compose.
  • Rutter — varje skärm identifieras av en ruttext med valfria sökvägs- och frågeparametrar.
  • Argument — skickas via NavArgument med stöd för primitiva, Parcelable och Serializable-typer.
  • Nästling — composable() stöder nästlade NavHost för modulär navigering med oberoende stackar.
  • Prestanda — lat initialisering av skärmar sparar minne, växlingstid mellan skärmar är 5–15 ms.
  • Fel — huvudsakliga problem: återskapande av NavController, oändlig recomposition vid anrop av navigate() i composable-kroppen, felaktig funktion av BottomNavigation.
  • Migrering — övergång från FragmentManager till composable() minskar mängden navigeringskod med 40–60% och eliminerar en klass av fel relaterade till Fragment-livscykeln.

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.

Diskutera projektet

Läs också