Auf dieser Seite finden Sie eine Anleitung zum Modularisieren Ihres Navigationscodes. Er soll die allgemeinen Hinweise zur Modularisierung von Apps ergänzen.
Übersicht
Bei der Modularisierung des Navigationscodes werden zusammengehörige Navigationsschlüssel und die von ihnen dargestellten Inhalte in einzelne Module aufgeteilt. So lassen sich die Verantwortlichkeiten klar trennen und Sie können zwischen verschiedenen Funktionen in Ihrer Anwendung wechseln.
So modularisieren Sie Ihren Navigationscode:
- Erstelle für jedes Feature in deiner App zwei Untermodule:
apiundimpl. - Navigationsschlüssel für jedes Feature im entsprechenden
api-Modul platzieren - Platziere
entryProvidersund navigierbare Inhalte für jedes Feature im zugehörigenimpl-Modul. - Stellen Sie
entryProvidersfür Ihre Haupt-App-Module bereit, entweder direkt oder mithilfe der Abhängigkeitsinjektion.
Funktionen in API- und Implementierungs-Submodule aufteilen
Erstellen Sie für jede Funktion in Ihrer App zwei Untermodule mit den Namen api und impl (kurz für „Implementierung“). Anhand der folgenden Tabelle können Sie entscheiden, wo Sie den Navigationscode platzieren möchten.
Modulname |
Enthält |
|
|
|
Inhalte für diese Funktion, einschließlich Definitionen für |
Bei diesem Ansatz kann von einer Funktion zu einer anderen navigiert werden, da der Inhalt im impl-Modul von den Navigationsschlüsseln eines anderen Moduls im api-Modul dieses Moduls abhängen kann.
Navigationseinträge mithilfe von Erweiterungsfunktionen trennen
In Navigation 3 werden navigierbare Inhalte mithilfe von Navigationseinträgen definiert. Wenn Sie diese Einträge in separate Module aufteilen möchten, erstellen Sie Erweiterungsfunktionen für EntryProviderScope und verschieben Sie sie in das impl-Modul für diese Funktion.
Diese werden als Eintrags-Builder bezeichnet.
Das folgende Codebeispiel zeigt einen Entry Builder, der zwei Navigationseinträge erstellt.
// 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 } } }
Rufen Sie diese Funktion mit der entryProvider-DSL auf, wenn Sie die entryProvider im Hauptmodul Ihrer Anwendung definieren.
// import androidx.navigation3.runtime.entryProvider // import androidx.navigation3.ui.NavDisplay NavDisplay( entryProvider = entryProvider { featureAEntryBuilder() }, // ... )
Abhängigkeitsinjektion verwenden, um der Haupt-App Einträge hinzuzufügen
Im vorherigen Codebeispiel wird jeder Entry Builder direkt von der Haupt-App mit der entryProvider-DSL aufgerufen. Wenn Ihre App viele Bildschirme oder Funktionsmodule hat, lässt sich dieses Muster möglicherweise nicht gut skalieren.
Um dieses Problem zu beheben, muss jedes Funktionsmodul seine Entry Builder mithilfe von Dependency Injection in die Aktivität der App einfügen.
Im folgenden Code werden beispielsweise Dagger-Multibindings, insbesondere @IntoSet, verwendet, um die Entry Builder in ein Set einzufügen, das zu MainActivity gehört. Diese werden dann iterativ in entryProvider aufgerufen, sodass keine expliziten Aufrufe zahlreicher Entry Builder-Funktionen erforderlich sind.
Funktionsmodul
// 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() } }
App-Modul
// 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() } }, // ... ) } } }
Wenn Ihre Navigationseinträge navigieren müssen, z. B. weil sie UI-Elemente enthalten, die zu neuen Bildschirmen navigieren, fügen Sie in jede Builder-Funktion ein Objekt ein, das den Navigationsstatus der App ändern kann.
Deeplink-Matcher modularisieren
Wenn deine App Deeplinks unterstützt und modularisiert ist, sollte jedes Funktionsmodul die DeepLinkMatcher-Instanzen für die eigenen Ziele definieren.
Wenn Sie alle Matcher aus Ihrer App zusammenfassen möchten, können Sie Multibindings für die Abhängigkeitsinjektion verwenden. Beispielsweise kann jedes Funktionsmodul seine Matcher zu einer Dagger-@IntoSet-Multibindung beitragen:
Funktionsmodul
@Module @InstallIn(ActivityRetainedComponent::class) object FeatureADeepLinkModule { @IntoSet @Provides fun provideUserMatcher(): DeepLinkMatcher<*, *> { return UriDeepLinkMatcher( DeepLinkUri("www.example.com/users/{id}"), serializer<UserProfileKey>() ) } }
Anschließend können Sie in Ihrem Hauptanwendungsmodul, z. B. in MainActivity, die Matcher einfügen und sie verwenden, um eingehende Anfragen abzugleichen:
App-Modul
@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) } } }
Weitere Informationen zum Definieren und Verarbeiten von Deeplinks finden Sie unter Deeplinks unterstützen.
Ressourcen
Codebeispiele für die Modularisierung von Navigation 3-Code finden Sie hier:
- Code-Rezepte für die Navigation 3-Architektur
- Der Lernpfad zur Modularisierung aus der Now in Android-App
- Androidify