Navigationscode modularisieren

Auf dieser Seite finden Sie eine Anleitung zur Modularisierung Ihres Navigationscodes. Sie soll die allgemeinen Hinweise zur App-Modularisierung ergänzen.

Übersicht

Beim Modularisieren des Navigationscodes werden zusammengehörige Navigationsschlüssel und die zugehörigen Inhalte in separate Module aufgeteilt. So lassen sich die Verantwortlichkeiten klar trennen und Sie können in Ihrer App zwischen verschiedenen Funktionen wechseln.

So modularisieren Sie Ihren Navigationscode:

  • Erstellen Sie zwei Untermodule: api und impl für jede Funktion in Ihrer App.
  • Platzieren Sie die Navigationsschlüssel für jede Funktion im zugehörigen api-Modul.
  • Platzieren Sie entryProviders und navigierbare Inhalte für jede Funktion im zugehörigen impl-Modul.
  • Stellen Sie entryProviders für Ihre Haupt-App-Module bereit, entweder direkt oder über die Abhängigkeitsinjektion.

Funktionen in API- und Implementierungsuntermodule 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.

Modulname

Enthält

api

Navigationstasten

impl

Inhalte für diese Funktion, einschließlich Definitionen für NavEntry und die entryProvider. Siehe auch Schlüssel zu Inhalten auflösen.

Bei diesem Ansatz kann eine Funktion zur anderen navigieren, indem die Inhalte des zugehörigen impl-Moduls von den Navigationsschlüsseln eines anderen Moduls abhängen, das im api-Modul enthalten ist.

Diagramm der Featuremodulabhängigkeiten, das zeigt, wie `impl`-Module von `api`-Modulen abhängen können.
Abbildung 1: Abhängigkeitsdiagramm für Feature-Module, das zeigt, wie Implementierungsmodule von API-Modulen abhängen können.

Navigationseinträge mit Erweiterungsfunktionen trennen

In Navigation 3 wird navigierbarer Inhalt über Navigationseinträge 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 Eintragsgeneratoren bezeichnet.

Das folgende Codebeispiel zeigt einen Eintrags-Builder, mit dem zwei Navigationseinträge erstellt werden.

// 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 entryProvider in Ihrem Haupt-App-Modul definieren.

// import androidx.navigation3.runtime.entryProvider
// import androidx.navigation3.ui.NavDisplay
NavDisplay(
    entryProvider = entryProvider {
        featureAEntryBuilder()
    },
    // ...
)

Einträge mithilfe der Abhängigkeitsinjektion zur Haupt-App hinzufügen

Im vorherigen Codebeispiel wird jeder Eintrags-Builder direkt von der Haupt-App über die entryProvider-DSL aufgerufen. Wenn Ihre App viele Bildschirme oder Funktionsmodule hat, ist das möglicherweise nicht gut skalierbar.

Um dieses Problem zu beheben, muss jedes Featuremodul seine Eintrags-Builder mithilfe der Abhängigkeitsinjektion in die Aktivität der App einbringen.

Im folgenden Code werden beispielsweise Dagger-Multibindings, insbesondere @IntoSet, verwendet, um die Eintrags-Builder in ein Set einzufügen, das zu MainActivity gehört. Diese werden dann iterativ in entryProvider aufgerufen, sodass nicht mehr zahlreiche Entry Builder-Funktionen explizit aufgerufen werden müssen.

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. wenn sie UI-Elemente enthalten, die zu neuen Bildschirmen führen, fügen Sie jeder Builder-Funktion ein Objekt hinzu, das den Navigationsstatus der App ändern kann.

Ressourcen

Codebeispiele für die Modularisierung von Navigation 3-Code finden Sie hier: