Questa pagina è una guida per la modularizzazione del codice di navigazione. È pensata per integrare le indicazioni generali per la modularizzazione delle app.
Panoramica
La modularizzazione del codice di navigazione è il processo di separazione delle chiavi di navigazione correlate e dei contenuti che rappresentano in singoli moduli. In questo modo, le responsabilità sono chiaramente separate e puoi spostarti tra le diverse funzionalità dell'app.
Per modularizzare il codice di navigazione:
- Crea due sottomoduli:
apieimplper ogni funzionalità dell'app - Inserisci le chiavi di navigazione per ogni funzionalità nel modulo
api - Inserisci
entryProviderse contenuti navigabili per ogni funzionalità nel moduloimplassociato - Fornisci
entryProvidersai moduli dell'app principale, direttamente o utilizzando l'iniezione delle dipendenze
Separare le funzionalità in sottomoduli API e di implementazione
Per ogni funzionalità dell'app, crea due sottomoduli denominati api e impl (abbreviazione di "implementazione"). Utilizza la tabella seguente per decidere dove inserire il codice di navigazione.
Nome modulo |
Contenuto |
|
|
|
Contenuti per la funzionalità, incluse le definizioni per
|
Questo approccio consente a una funzionalità di passare a un'altra consentendo ai contenuti, contenuti nel modulo impl, di dipendere dalle chiavi di navigazione di un altro modulo, contenute nel modulo api di quel modulo.
Separare le voci di navigazione utilizzando le funzioni di estensione
In Navigazione 3, i contenuti navigabili vengono definiti utilizzando le voci di navigazione. Per
separare queste voci in moduli separati, crea funzioni di estensione su
EntryProviderScope e spostale nel modulo impl per quella funzionalità.
Questi sono noti come generatori di voci.
Il seguente esempio di codice mostra un generatore di voci che crea due voci di navigazione.
// import androidx.navigation3.runtime.EntryProviderScope // import androidx.navigation3.runtime.NavKey fun EntryProviderScope<NavKey>.featureAEntryBuilder() { entry<KeyA> { ContentRed("Screen A") { // Content for screen A } } entry<KeyA2> { ContentGreen("Screen A2") { // Content for screen A2 } } }
Chiama quella funzione utilizzando il DSL entryProvider quando definisci il tuo
entryProvider nel modulo dell'app principale.
// import androidx.navigation3.runtime.entryProvider // import androidx.navigation3.ui.NavDisplay NavDisplay( entryProvider = entryProvider { featureAEntryBuilder() }, // ... )
Utilizzare l'iniezione delle dipendenze per aggiungere voci all'app principale
Nell'esempio di codice precedente, ogni generatore di voci viene chiamato direttamente dall'app principale utilizzando il DSL entryProvider. Se la tua app ha molti schermi o moduli di funzionalità, questo pattern potrebbe non essere scalabile.
Per risolvere questo problema, fai in modo che ogni modulo della funzionalità contribuisca con i propri generatori di voci all'attività dell'app utilizzando l'iniezione delle dipendenze.
Ad esempio, il seguente codice utilizza i multibinding Dagger,
in particolare @IntoSet, per inserire i generatori di voci in un Set di proprietà di
MainActivity. Questi vengono poi chiamati in modo iterativo all'interno di entryProvider, eliminando la necessità di chiamare esplicitamente numerose funzioni di generazione di voci.
Modulo delle funzionalità
// import dagger.Module // import dagger.Provides // import dagger.hilt.InstallIn // import dagger.hilt.android.components.ActivityRetainedComponent // import dagger.multibindings.IntoSet @Module @InstallIn(ActivityRetainedComponent::class) object FeatureAModule { @IntoSet @Provides fun provideFeatureAEntryBuilder() : EntryProviderScope<NavKey>.() -> Unit = { featureAEntryBuilder() } }
Modulo dell'app
// import android.os.Bundle // import androidx.activity.ComponentActivity // import androidx.activity.compose.setContent // import androidx.navigation3.runtime.EntryProviderScope // import androidx.navigation3.runtime.NavKey // import androidx.navigation3.runtime.entryProvider // import androidx.navigation3.ui.NavDisplay // import javax.inject.Inject class MainActivity : ComponentActivity() { @Inject lateinit var entryBuilders: Set<@JvmSuppressWildcards EntryProviderScope<NavKey>.() -> Unit> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { NavDisplay( entryProvider = entryProvider { entryBuilders.forEach { builder -> this.builder() } }, // ... ) } } }
Se le voci di navigazione devono navigare, ad esempio contengono elementi dell'interfaccia utente che rimandano a nuove schermate, inserisci un oggetto in grado di modificare lo stato di navigazione dell'app in ogni funzione di generazione.
Modularizzare i matcher di link diretti
Se la tua app supporta i link diretti ed è modularizzata, ogni modulo della funzionalità deve definire le istanze DeepLinkMatcher per le destinazioni di cui è proprietario.
Per raccogliere tutti i matcher dell'app, puoi utilizzare i multibinding di iniezione delle dipendenze. Ad esempio, ogni modulo della funzionalità può contribuire con i propri matcher a un multibinding Dagger @IntoSet:
Modulo delle funzionalità
@Module @InstallIn(ActivityRetainedComponent::class) object FeatureADeepLinkModule { @IntoSet @Provides fun provideUserMatcher(): DeepLinkMatcher<*, *> { return UriDeepLinkMatcher( DeepLinkUri("www.example.com/users/{id}"), serializer<UserProfileKey>() ) } }
Poi, nel modulo dell'app principale, ad esempio in MainActivity, puoi inserire l'insieme di matcher e utilizzarli per abbinare le richieste in entrata:
Modulo dell'app
@AndroidEntryPoint class MainActivityWithDI : ComponentActivity() { @Inject lateinit var deepLinkMatchers: Set<@JvmSuppressWildcards DeepLinkMatcher<*, *>> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val request = DeepLinkRequest(intent = intent) val matchResult = deepLinkMatchers .mapNotNull { it.match(request) } .maxOrNull() val backStack = when (matchResult) { null -> listOf(HomeKey) is BackStackMatchResult<*, *> -> { @Suppress("UNCHECKED_CAST") matchResult.backStack as List<NavKey> } else -> listOf(matchResult.key) } } }
Per ulteriori informazioni sulla definizione e sulla gestione dei link diretti, consulta Supportare i link diretti.
Risorse
Per esempi di codice che mostrano come modularizzare il codice di Navigazione 3, consulta:
- Le ricette di codice dell'architettura di Navigazione 3
- Il percorso di apprendimento della modularizzazione dell'app Now in Android
- Androidify