Sprawdzone metody nawigacji w projektach opartych na wielu modułach

Wykres nawigacyjny może składać się z dowolnej kombinacji następujących elementów:

  • Pojedyncze miejsce docelowe, np. <fragment>.
  • Zagnieżdżony wykres obejmujący zbiór powiązanych miejsc docelowych.
  • Element <include>, który umożliwia umieszczenie innego pliku wykresu nawigacyjnego, jak gdyby był on zagnieżdżony.

Ta elastyczność pozwala łączyć mniejsze wykresy nawigacyjne, aby utworzyć pełny wykres nawigacyjny aplikacji, nawet jeśli te mniejsze wykresy nawigacyjne są wyposażone w osobne moduły.

.

W przypadku przykładów z tego tematu każdy moduł funkcji skupia się na 1 funkcji i zawiera jeden wykres nawigacyjny obejmujący wszystkie miejsca docelowe potrzebne do implementacji tej funkcji. W aplikacji produkcyjnej może znajdować się wiele modułów podrzędnych na niższym poziomie, które zawierają szczegóły implementacji modułu funkcji wyższego poziomu. Każdy z tych modułów funkcji jest uwzględniany (bezpośrednio lub pośrednio) w module app. Przykładowa aplikacja składająca się z wielu modułów użyta w tym dokumencie ma taką strukturę:

wykres zależności dla przykładowej aplikacji składającej się z wielu modułów
początkowe miejsce docelowe przykładowej aplikacji
Rysunek 1. Architektura aplikacji i miejsce docelowe dla przykładowej aplikacji.

Każdy moduł funkcji jest samodzielną jednostką z własnym wykresem nawigacyjnym i miejscami docelowymi. Moduł app zależy od każdego z nich i dodaje je jako szczegóły implementacji w pliku build.gradle, jak na przykładzie:

Odlotowy

dependencies {
    ...
    implementation project(":feature:home")
    implementation project(":feature:favorites")
    implementation project(":feature:settings")

Kotlin

dependencies {
    ...
    implementation(project(":feature:home"))
    implementation(project(":feature:favorites"))
    implementation(project(":feature:settings"))

Rola modułu app

Moduł app odpowiada za pokazanie pełnego wykresu Twojej aplikacji i dodanie do interfejsu NavHost modułu. Na wykresie nawigacyjnym w module app możesz odwoływać się do wykresów bibliotecznych za pomocą funkcji <include>. Chociaż funkcja <include> działa tak samo jak graf zagnieżdżony, <include> obsługuje wykresy z innych modułów projektu lub projektów bibliotecznych, jak w tym przykładzie:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/home_nav_graph">

    <include app:graph="@navigation/home_navigation" />
    <include app:graph="@navigation/favorites_navigation" />
    <include app:graph="@navigation/settings_navigation" />
</navigation>

W razie potrzeby po dodaniu biblioteki do wykresu nawigacyjnego najwyższego poziomu możesz przejść do niego. W ten sposób możesz np. przejść do wykresu ustawień z fragmentu wykresu nawigacyjnego:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/home_nav_graph">

    <include app:graph="@navigation/home_navigation" />
    <include app:graph="@navigation/favorites_navigation" />
    <include app:graph="@navigation/settings_navigation" />

    <fragment
        android:id="@+id/random_fragment"
        android:name="com.example.android.RandomFragment"
        android:label="@string/fragment_random" >
        <!-- Launch into Settings Navigation Graph -->
        <action
            android:id="@+id/action_random_fragment_to_settings_nav_graph"
            app:destination="@id/settings_nav_graph" />
    </fragment>
</navigation>

Jeśli wiele modułów funkcji musi odwoływać się do wspólnego zestawu miejsc docelowych, np. do wykresu logowania, nie należy dodawać tych popularnych miejsc docelowych do wykresu nawigacji każdego modułu funkcji. Zamiast tego dodaj te wspólne miejsca docelowe do wykresu nawigacyjnego w module app. Każdy moduł funkcji może następnie przechodzić między modułami funkcji, aby przechodzić do tych typowych miejsc docelowych.

W poprzednim przykładzie działanie wskazuje miejsce docelowe nawigacji @id/settings_nav_graph. Ten identyfikator odnosi się do miejsca docelowego określonego na uwzględnionym wykresie @navigation/settings_navigation.

Nawigacja najwyższego poziomu w module aplikacji

Komponent Nawigacja zawiera klasę NavigationUI. Ta klasa zawiera metody statyczne zarządzające nawigacją za pomocą górnego paska aplikacji, panelu nawigacji i dolnego obszaru nawigacyjnego. Jeśli miejsca docelowe najwyższego poziomu aplikacji składają się z elementów interfejsu dostarczanych przez moduły funkcji, moduł app jest naturalnym miejscem, w którym można umieścić elementy nawigacyjne i elementy interfejsu najwyższego poziomu. Moduł aplikacji wymaga współpracy modułów funkcji, więc wszystkie ich miejsca docelowe są dostępne z poziomu kodu zdefiniowanego w module aplikacji. Oznacza to, że za pomocą polecenia NavigationUI możesz wiązać miejsca docelowe z pozycjami menu, jeśli identyfikator elementu jest taki sam jak identyfikator miejsca docelowego.

Na rysunku 2 przykładowy moduł app określa element BottomNavigationView w swojej głównej aktywności. Identyfikatory pozycji menu w menu odpowiadają identyfikatorom wykresów nawigacyjnych na wykresach bibliotecznych:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@id/home_nav_graph"
        android:icon="@drawable/ic_home"
        android:title="Home"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@id/favorites_nav_graph"
        android:icon="@drawable/ic_favorite"
        android:title="Favorites"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@id/settings_nav_graph"
        android:icon="@drawable/ic_settings"
        android:title="Settings"
        app:showAsAction="ifRoom" />
</menu>

Aby umożliwić NavigationUI obsługę dolnego nawigacji, wywołaj setupWithNavController() z onCreate() w głównej klasie aktywności, jak pokazano w tym przykładzie:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController

    findViewById<BottomNavigationView>(R.id.bottom_nav)
            .setupWithNavController(navController)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    NavHostFragment navHostFragment =
            (NavHostFragment) supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    BottomNavigationView bottomNav = findViewById(R.id.bottom_nav);

    NavigationUI.setupWithNavController(bottomNav, navController);
}

Gdy użytkownik kliknie ten element nawigacyjny, NavigationUI przejdzie do odpowiedniego wykresu biblioteki.

Pamiętaj, że w przypadku modułu aplikacji głęboko zależność od konkretnego miejsca docelowego umieszczonego głęboko w wykresie nawigacji modułów funkcji jest ogólnie niewskazaną praktyką. Najczęściej moduł aplikacji powinien znać tylko punkt wejścia do umieszczonych lub dołączonych wykresów nawigacyjnych (dotyczy to również poza modułami funkcji). Jeśli chcesz dodać link do miejsca docelowego umieszczony głębiej na wykresie nawigacyjnym biblioteki, najlepiej użyć precyzyjnego linku. Precyzyjne linki są też jedynym sposobem przejścia biblioteki do miejsca docelowego na wykresie nawigacyjnym innej biblioteki.

Przechodzenie między modułami funkcji

W czasie kompilacji niezależne moduły funkcji nie widzą się nawzajem, więc nie możesz używać identyfikatorów do przechodzenia do miejsc docelowych w innych modułach. Zamiast tego użyj precyzyjnego linku, aby przejść bezpośrednio do miejsca docelowego powiązanego z ukrytym precyzyjnym linkiem.

Kontynuując poprzedni przykład, załóżmy, że musisz przejść z przycisku w module :feature:home do miejsca docelowego umieszczonego w module :feature:settings. Możesz to zrobić, dodając precyzyjny link do miejsca docelowego na wykresie nawigacyjnym ustawień, jak pokazano poniżej:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/settings_nav_graph"
    app:startDestination="@id/settings_fragment_one">

    ...

    <fragment
        android:id="@+id/settings_fragment_two"
        android:name="com.example.google.login.SettingsFragmentTwo"
        android:label="@string/settings_fragment_two" >

        <deepLink
            app:uri="android-app://example.google.app/settings_fragment_two" />
    </fragment>
</navigation>

Następnie dodaj następujący kod do sekcji onClickListener przycisku we fragmencie głównym:

Kotlin

button.setOnClickListener {
    val request = NavDeepLinkRequest.Builder
        .fromUri("android-app://example.google.app/settings_fragment_two".toUri())
        .build()
    findNavController().navigate(request)
}

Java

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        NavDeepLinkRequest request = NavDeepLinkRequest.Builder
            .fromUri(Uri.parse("android-app://example.google.app/settings_fragment_two"))
            .build();
        NavHostFragment.findNavController(this).navigate(request);
    }
});

W przeciwieństwie do nawigacji przy użyciu identyfikatorów działań lub miejsc docelowych możesz przejść do dowolnego identyfikatora URI na dowolnym wykresie, a nawet w obrębie modułów.

Podczas nawigowania za pomocą identyfikatora URI stos wsteczny nie jest resetowany. W przeciwieństwie do bezpośredniej nawigacji po precyzyjnych linkach, gdzie podczas nawigowania stos tylny jest zastępowany.