0Pricing
Android Academy · Lezione

Navigazione tra moduli

Colleghi le funzionalità senza creare accoppiamento

Navigazione tra moduli è una lezione Android Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Android Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Android Academy include 4 lezioni in totale.

La sfida della navigazione

Quando le funzionalità risiedono in moduli separati, si presenta una nuova domanda: come può :feature:home aprire una schermata in :feature:profile senza dipendere da essa? Se le funzionalità si importano direttamente a vicenda, si crea accoppiamento e si rischiano cicli.

In questa lezione collegherà le funzionalità tramite la navigazione, mantenendole indipendenti.

Dove risiede il NavHost

L'unico NavHost risiede nel modulo :app, l'unico punto autorizzato a conoscere tutte le funzionalità. Ogni funzionalità contribuisce con le proprie destinazioni e :app le assembla in un unico grafo.

// app/AppNavHost.kt
@Composable
fun AppNavHost(navController: NavHostController = rememberNavController()) {
    NavHost(navController, startDestination = HomeRoute) {
        homeScreen(onProfileClick = { navController.navigate(ProfileRoute) })
        profileScreen(onBack = { navController.popBackStack() })
    }
}

Route type-safe

Navigation Compose moderno supporta le route type-safe: una route è un oggetto o una data class @Serializable, non una stringa arbitraria. Ogni funzionalità definisce il proprio tipo di route nel rispettivo modulo, che diventa così proprietario del contratto di navigazione.

// feature/profile/ProfileRoute.kt
import kotlinx.serialization.Serializable

@Serializable
data class ProfileRoute(val userId: String)

Le funzionalità espongono estensioni di NavGraphBuilder

Il punto fondamentale è questo: ogni funzionalità espone una funzione di estensione di NavGraphBuilder che registra la propria destinazione. La funzionalità è proprietaria della propria schermata; :app si limita a chiamare questa funzione. La funzionalità non fa mai riferimento alle altre funzionalità.

// feature/profile/ProfileNavigation.kt
fun NavGraphBuilder.profileScreen(onBack: () -> Unit) {
    composable<ProfileRoute> { backStackEntry ->
        val route: ProfileRoute = backStackEntry.toRoute()
        ProfileScreen(userId = route.userId, onBack = onBack)
    }
}

Disaccoppiare con callback di navigazione

Una funzionalità non deve mai chiamare direttamente navigate(SomeOtherFeatureRoute), perché ciò richiederebbe una dipendenza dall'altra funzionalità. In alternativa, esponga callback lambda come onProfileClick. Il modulo :app decide dove conducono effettivamente.

// feature/home/HomeNavigation.kt
fun NavGraphBuilder.homeScreen(onProfileClick: (String) -> Unit) {
    composable<HomeRoute> {
        HomeScreen(onUserClick = { userId -> onProfileClick(userId) })
    }
}
// :home does NOT know ProfileRoute exists.

Il modulo :app collega tutto

Solo il modulo :app conosce tutte le route e collega i callback alla navigazione reale. Questo è l'unico punto in cui l'accoppiamento è accettabile: il suo intero compito è l'assemblaggio.

// app/AppNavHost.kt
NavHost(navController, startDestination = HomeRoute) {
    homeScreen(
        onProfileClick = { userId ->
            navController.navigate(ProfileRoute(userId)) // app knows both
        }
    )
    profileScreen(onBack = { navController.popBackStack() })
}

Passare gli argomenti in modo sicuro

Poiché le route sono data class @Serializable, gli argomenti vengono verificati a livello di compilazione. Li recupera con toRoute() all'interno della destinazione. Non dovrà più analizzare stringhe né affrontare arresti anomali a runtime causati da 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()

Condividere i tipi di route tramite un modulo api

A volte una funzionalità ha davvero bisogno di navigare verso un'altra e di utilizzare il tipo di route. Invece di dipendere dall'intera funzionalità, esponga la sola route in un piccolo modulo :feature:profile:api contenente esclusivamente la route @Serializable. Il modulo pesante :impl rimane privato.

// 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"))

Navigazione annidata per funzionalità

Una funzionalità con diverse schermate può esporre un intero grafo annidato utilizzando navigation<T>. La funzionalità è proprietaria del proprio flusso interno; :app si limita a montare il grafo in un unico punto di ingresso.

// feature/onboarding/OnboardingNavigation.kt
fun NavGraphBuilder.onboardingGraph(onFinished: () -> Unit) {
    navigation<OnboardingGraph>(startDestination = WelcomeRoute) {
        composable<WelcomeRoute> { WelcomeScreen() }
        composable<PermissionsRoute> { PermissionsScreen(onDone = onFinished) }
    }
}

Deep link tra moduli

Le route type-safe supportano anche i deep link. Una funzionalità dichiara un modello URI di deep link per la propria destinazione; il NavHost di :app risolve un link in ingresso indirizzandolo alla schermata corretta della funzionalità, senza bisogno di import tra funzionalità.

composable<ProfileRoute>(
    deepLinks = listOf(
        navDeepLink<ProfileRoute>(basePath = "https://myapp.com/profile")
    )
) { entry ->
    ProfileScreen(userId = entry.toRoute<ProfileRoute>().userId)
}

Riepilogo dello schema di disaccoppiamento

In sintesi, le regole sono semplici:

  • Ogni funzionalità è proprietaria del proprio tipo di route e di un'estensione di NavGraphBuilder.
  • Le funzionalità comunicano l'intenzione tramite callback lambda, non tramite navigazione diretta.
  • Solo :app conosce tutte le funzionalità e collega i callback alle route reali.
  • Se una route deve essere condivisa, la esponga tramite un piccolo modulo :api.

In questo modo le funzionalità rimangono indipendenti, compatibili con la build cache e prive di cicli.

Verifica rapida

In un'app multi-modulo, :feature:home deve portare l'utente a una schermata in :feature:profile. Qual è il modo più pulito per mantenere disaccoppiate le funzionalità?

Riepilogo: navigazione tra moduli

Ha imparato a collegare le funzionalità senza accoppiarle:

  • L'unico NavHost risiede nel modulo :app, che rimane sottile.
  • Ogni funzionalità è proprietaria di una route @Serializable e di un'estensione di NavGraphBuilder.
  • Le funzionalità espongono callback invece di navigare direttamente verso altre funzionalità.
  • Condivida una route solo tramite un piccolo modulo :api quando è realmente necessario; deep link e grafi annidati seguono lo stesso schema.

Con questo si conclude l'architettura di app multi-modulo: ora può suddividere, collegare e gestire la navigazione in un codebase Android scalabile.

Domande Frequenti

La lezione «Navigazione tra moduli» è gratuita?

Sì — il testo completo di «Navigazione tra moduli» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Android Academy, passa a CoddyKit PRO. Il corso Android Academy include 4 lezioni in totale.

Cosa imparerò in «Navigazione tra moduli»?

Colleghi le funzionalità senza creare accoppiamento Eserciti Android Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Android Academy?

Non è richiesta alcuna esperienza precedente. Android Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Navigazione tra moduli»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Android Academy?

Sì. Ogni lezione Android Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Perché modularizzare
  2. Moduli feature e core
  3. Gestire le dipendenze tra moduli
  4. Navigazione tra moduli
← Torna a Android Academy