Navigation entre modules
Reliez les fonctionnalités sans couplage.
Navigation entre modules est une leçon Android Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Android Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Android Academy comprend 4 leçons au total.
Le défi de la navigation
Une fois les fonctionnalités placées dans des modules distincts, une nouvelle question se pose : comment :feature:home peut-il ouvrir un écran de :feature:profile sans en dépendre ? Si les fonctionnalités s'importent directement l'une l'autre, vous créez un couplage et risquez de former des cycles.
Dans cette leçon, vous apprendrez à relier les fonctionnalités par la navigation tout en les gardant indépendantes.
Où se trouve le NavHost
L'unique NavHost se trouve dans le module :app, le seul endroit autorisé à connaître toutes les fonctionnalités. Chaque fonctionnalité fournit ses destinations, et :app les assemble en un seul graphe.
// app/AppNavHost.kt
@Composable
fun AppNavHost(navController: NavHostController = rememberNavController()) {
NavHost(navController, startDestination = HomeRoute) {
homeScreen(onProfileClick = { navController.navigate(ProfileRoute) })
profileScreen(onBack = { navController.popBackStack() })
}
}Routes fortement typées
Navigation Compose moderne prend en charge les routes fortement typées : une route est un objet ou une classe de données @Serializable, et non une chaîne magique. Chaque fonctionnalité définit son propre type de route dans son module et possède ainsi son contrat de navigation.
// feature/profile/ProfileRoute.kt
import kotlinx.serialization.Serializable
@Serializable
data class ProfileRoute(val userId: String)Les fonctionnalités exposent des extensions de NavGraphBuilder
L'astuce principale est la suivante : chaque fonctionnalité expose une fonction d'extension de NavGraphBuilder qui enregistre sa destination. La fonctionnalité possède son écran ; :app se contente d'appeler cette fonction. La fonctionnalité ne fait jamais référence aux autres fonctionnalités.
// feature/profile/ProfileNavigation.kt
fun NavGraphBuilder.profileScreen(onBack: () -> Unit) {
composable<ProfileRoute> { backStackEntry ->
val route: ProfileRoute = backStackEntry.toRoute()
ProfileScreen(userId = route.userId, onBack = onBack)
}
}Découpler avec des rappels de navigation
Une fonctionnalité ne doit jamais appeler directement navigate(SomeOtherFeatureRoute), car cela l'obligerait à dépendre de l'autre fonctionnalité. À la place, elle expose des rappels lambda tels que onProfileClick. Le module :app décide de leur destination réelle.
// feature/home/HomeNavigation.kt
fun NavGraphBuilder.homeScreen(onProfileClick: (String) -> Unit) {
composable<HomeRoute> {
HomeScreen(onUserClick = { userId -> onProfileClick(userId) })
}
}
// :home does NOT know ProfileRoute exists.Le module :app relie tous les éléments
Seul le module :app connaît toutes les routes et relie les rappels à la navigation réelle. C'est le seul endroit où le couplage est acceptable : son rôle entier est l'assemblage.
// app/AppNavHost.kt
NavHost(navController, startDestination = HomeRoute) {
homeScreen(
onProfileClick = { userId ->
navController.navigate(ProfileRoute(userId)) // app knows both
}
)
profileScreen(onBack = { navController.popBackStack() })
}Transmettre des arguments en toute sécurité
Comme les routes sont des classes de données @Serializable, les arguments sont vérifiés par le compilateur. Vous les relisez avec toRoute() à l'intérieur de la destination. Fini l'analyse de chaînes et les plantages à l'exécution causés par 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()Partager les types de route via un module api
Il arrive qu'une fonctionnalité doive réellement naviguer vers une autre et ait besoin de son type de route. Plutôt que de dépendre de toute la fonctionnalité, exposez uniquement la route dans un petit module :feature:profile:api contenant seulement la route @Serializable. Le module lourd :impl reste privé.
// 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"))Navigation imbriquée par fonctionnalité
Une fonctionnalité comportant plusieurs écrans peut exposer un graphe imbriqué complet avec navigation<T>. La fonctionnalité possède son parcours interne ; :app se contente de monter le graphe à un seul point d'entrée.
// feature/onboarding/OnboardingNavigation.kt
fun NavGraphBuilder.onboardingGraph(onFinished: () -> Unit) {
navigation<OnboardingGraph>(startDestination = WelcomeRoute) {
composable<WelcomeRoute> { WelcomeScreen() }
composable<PermissionsRoute> { PermissionsScreen(onDone = onFinished) }
}
}Liens profonds entre modules
Les routes fortement typées prennent également en charge les liens profonds. Une fonctionnalité déclare un modèle d'URI de lien profond pour sa destination ; le NavHost de :app dirige un lien entrant vers l'écran de la bonne fonctionnalité, sans nécessiter d'import entre fonctionnalités.
composable<ProfileRoute>(
deepLinks = listOf(
navDeepLink<ProfileRoute>(basePath = "https://myapp.com/profile")
)
) { entry ->
ProfileScreen(userId = entry.toRoute<ProfileRoute>().userId)
}Résumé du modèle de découplage
En résumé, les règles sont simples :
- Chaque fonctionnalité possède son type de route et une extension de NavGraphBuilder.
- Les fonctionnalités communiquent leur intention par des rappels lambda, et non par une navigation directe.
- Seul :app connaît toutes les fonctionnalités et relie les rappels aux routes réelles.
- Si une route doit être partagée, exposez-la via un petit module :api.
Ainsi, les fonctionnalités restent indépendantes, compatibles avec le cache de compilation et exemptes de cycles.
Vérification rapide
Dans une application composée de plusieurs modules, :feature:home doit envoyer l'utilisateur vers un écran de :feature:profile. Quelle est la meilleure façon de garder les fonctionnalités découplées ?
Récapitulatif : navigation entre modules
Vous avez appris à relier les fonctionnalités sans les coupler :
- L'unique
NavHostse trouve dans le module :app minimal. - Chaque fonctionnalité possède une route
@Serializableet une extension deNavGraphBuilder. - Les fonctionnalités exposent des rappels au lieu de naviguer directement vers d'autres fonctionnalités.
- Ne partagez une route via un petit module :api que lorsque c'est réellement nécessaire ; les liens profonds et les graphes imbriqués suivent le même modèle.
Vous avez terminé l'architecture d'application Android multi-module : vous pouvez désormais découper, relier et faire naviguer une base de code Android évolutive.
Questions Fréquemment Posées
La leçon « Navigation entre modules » est-elle gratuite ?
Oui — le texte complet de « Navigation entre modules » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Android Academy, passe à CoddyKit PRO. Le cours Android Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Navigation entre modules » ?
Reliez les fonctionnalités sans couplage. Tu pratiques Android Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Android Academy ?
Aucune expérience préalable n'est requise. Android Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Navigation entre modules » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Android Academy ?
Oui. Chaque leçon Android Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Pourquoi modulariser
- Modules de fonctionnalités et modules centraux
- Gérer les dépendances entre modules
- Navigation entre modules