Navigation über Module hinweg
Features ohne enge Kopplung verbinden
Navigation über Module hinweg ist eine kostenlose Android Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Android Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Android Academy-Kurs umfasst insgesamt 4 Lektionen.
Die Navigationsherausforderung
Sobald sich Features in separaten Modulen befinden, stellt sich eine neue Frage: Wie kann :feature:home einen Screen in :feature:profile öffnen, ohne davon abzuhängen? Wenn Features direkt voneinander importieren, entsteht eine enge Kopplung und es besteht die Gefahr von Zyklen.
In dieser Lektion lernen Sie, Features über die Navigation zu verbinden und dabei unabhängig zu halten.
Wo sich der NavHost befindet
Der einzige NavHost befindet sich im :app-Modul, dem einzigen Ort, der alle Features kennen darf. Jedes Feature steuert seine Ziele bei, und :app setzt daraus einen gemeinsamen Graphen zusammen.
// app/AppNavHost.kt
@Composable
fun AppNavHost(navController: NavHostController = rememberNavController()) {
NavHost(navController, startDestination = HomeRoute) {
homeScreen(onProfileClick = { navController.navigate(ProfileRoute) })
profileScreen(onBack = { navController.popBackStack() })
}
}Typsichere Routen
Modernes Navigation Compose unterstützt typsichere Routen: Eine Route ist ein @Serializable-Objekt oder eine Data Class und keine magische Zeichenfolge. Jedes Feature definiert seinen eigenen Routentyp in seinem Modul und besitzt damit seinen Navigationsvertrag.
// feature/profile/ProfileRoute.kt
import kotlinx.serialization.Serializable
@Serializable
data class ProfileRoute(val userId: String)Features stellen NavGraphBuilder-Erweiterungen bereit
Der entscheidende Kniff: Jedes Feature stellt eine Erweiterungsfunktion für NavGraphBuilder bereit, die sein Ziel registriert. Das Feature besitzt seinen Screen; :app ruft lediglich diese Funktion auf. Das Feature verweist niemals auf andere Features.
// feature/profile/ProfileNavigation.kt
fun NavGraphBuilder.profileScreen(onBack: () -> Unit) {
composable<ProfileRoute> { backStackEntry ->
val route: ProfileRoute = backStackEntry.toRoute()
ProfileScreen(userId = route.userId, onBack = onBack)
}
}Entkopplung mit Navigations-Callbacks
Ein Feature darf niemals direkt navigate(SomeOtherFeatureRoute) aufrufen, da es dadurch vom anderen Feature abhängig wäre. Stattdessen stellt das Feature Lambda-Callbacks wie onProfileClick bereit. Das :app-Modul entscheidet, wohin sie tatsächlich navigieren.
// feature/home/HomeNavigation.kt
fun NavGraphBuilder.homeScreen(onProfileClick: (String) -> Unit) {
composable<HomeRoute> {
HomeScreen(onUserClick = { userId -> onProfileClick(userId) })
}
}
// :home does NOT know ProfileRoute exists.Das :app-Modul verbindet alles
Nur das :app-Modul kennt alle Routen und verbindet die Callbacks mit der tatsächlichen Navigation. Dies ist der eine Ort, an dem Kopplung akzeptabel ist – seine gesamte Aufgabe besteht im Zusammensetzen.
// app/AppNavHost.kt
NavHost(navController, startDestination = HomeRoute) {
homeScreen(
onProfileClick = { userId ->
navController.navigate(ProfileRoute(userId)) // app knows both
}
)
profileScreen(onBack = { navController.popBackStack() })
}Argumente sicher übergeben
Da Routen @Serializable-Data-Classes sind, werden Argumente zur Compile-Zeit typgeprüft. Innerhalb des Ziels lesen Sie sie mit toRoute() wieder aus. Keine String-Verarbeitung mehr und keine Abstürze zur Laufzeit durch arguments?.getString(...).
// Reading arguments inside the destination
composable<ProfileRoute> { entry ->
val args: ProfileRoute = entry.toRoute()
ProfileScreen(userId = args.userId)
}
// Or directly in a ViewModel via SavedStateHandle
val route: ProfileRoute = savedStateHandle.toRoute()Routentypen über ein api-Modul gemeinsam nutzen
Manchmal muss ein Feature tatsächlich zu einem anderen navigieren und benötigt dessen Routentyp. Statt vom gesamten Feature abzuhängen, stellen Sie die Route in einem kleinen :feature:profile:api-Modul bereit, das nur die @Serializable-Route enthält. Das umfangreiche :impl-Modul bleibt privat.
// feature/profile/api -> only the route type
@Serializable
data class ProfileRoute(val userId: String)
// feature/home/build.gradle.kts
// home may depend on the lightweight api to build the route,
// but never on :feature:profile:impl
implementation(project(":feature:profile:api"))Verschachtelte Navigation pro Feature
Ein Feature mit mehreren Screens kann einen vollständigen verschachtelten Graphen mit navigation<T> bereitstellen. Das Feature besitzt seinen internen Ablauf; :app bindet den Graphen lediglich an einem Einstiegspunkt ein.
// feature/onboarding/OnboardingNavigation.kt
fun NavGraphBuilder.onboardingGraph(onFinished: () -> Unit) {
navigation<OnboardingGraph>(startDestination = WelcomeRoute) {
composable<WelcomeRoute> { WelcomeScreen() }
composable<PermissionsRoute> { PermissionsScreen(onDone = onFinished) }
}
}Deep Links über Module hinweg
Typsichere Routen unterstützen auch Deep Links. Ein Feature deklariert für sein Ziel ein URI-Muster für Deep Links; der :app-NavHost ordnet einen eingehenden Link dem richtigen Feature-Screen zu, ohne dass ein Feature-übergreifender Import erforderlich ist.
composable<ProfileRoute>(
deepLinks = listOf(
navDeepLink<ProfileRoute>(basePath = "https://myapp.com/profile")
)
) { entry ->
ProfileScreen(userId = entry.toRoute<ProfileRoute>().userId)
}Das Entkopplungsmuster zusammengefasst
Zusammengefasst sind die Regeln einfach:
- Jedes Feature besitzt seinen Routentyp und eine NavGraphBuilder-Erweiterung.
- Features teilen ihre Absicht über Lambda-Callbacks mit, nicht über direkte Navigation.
- Nur :app kennt alle Features und verbindet die Callbacks mit den tatsächlichen Routen.
- Wenn eine Route gemeinsam genutzt werden muss, stellen Sie sie über ein kleines :api-Modul bereit.
So bleiben Features unabhängig, für den Build-Cache geeignet und frei von Zyklen.
Kurze Überprüfung
In einer App mit mehreren Modulen muss :feature:home den Benutzer zu einem Screen in :feature:profile weiterleiten. Was ist der sauberste Weg, die Features zu entkoppeln?
Zusammenfassung: Navigation über Module hinweg
Sie haben gelernt, Features zu verbinden, ohne sie eng zu koppeln:
- Der einzige
NavHostbefindet sich im schlanken :app-Modul. - Jedes Feature besitzt eine
@Serializable-Route und eineNavGraphBuilder-Erweiterung. - Features stellen Callbacks bereit, statt direkt zu anderen Features zu navigieren.
- Teilen Sie eine Route nur dann über ein kleines :api-Modul, wenn dies wirklich erforderlich ist; Deep Links und verschachtelte Graphen folgen demselben Muster.
Damit ist die Architektur mehrmodularer Apps abgeschlossen: Sie können jetzt eine skalierbare Android-Codebasis aufteilen, verbinden und Navigation darin umsetzen.
Häufig gestellte Fragen
Ist die Lektion „Navigation über Module hinweg“ kostenlos?
Ja — der vollständige Text von „Navigation über Module hinweg“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Android Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Android Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Navigation über Module hinweg“?
Features ohne enge Kopplung verbinden Du übst Android Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Android Academy zu starten?
Keine Vorkenntnisse erforderlich. Android Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Navigation über Module hinweg“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Android Academy-Lektion Code schreiben und ausführen?
Ja. Jede Android Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Warum modularisieren?
- Feature- und Core-Module
- Modulabhängigkeiten verwalten
- Navigation über Module hinweg