Android Academy · Lekcja

Nawigacja między modułami

Łącz funkcje bez ścisłego powiązania

Lekcja 4 z 413 kroki

Nawigacja między modułami to bezpłatna lekcja Android Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Android Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Android Academy zawiera 4 lekcji w sumie.

Wyzwanie związane z nawigacją

Gdy funkcjonalności znajdują się w osobnych modułach, pojawia się nowe pytanie: jak :feature:home może otworzyć ekran w :feature:profile bez zależności od tego modułu? Jeśli funkcjonalności będą importować się bezpośrednio, powstanie silne powiązanie i ryzyko cykli.

W tej lekcji nauczysz się łączyć funkcjonalności za pomocą nawigacji, zachowując ich niezależność.

Gdzie znajduje się NavHost

Pojedynczy NavHost znajduje się w module :app — jedynym miejscu, które może znać wszystkie funkcjonalności. Każda funkcjonalność dostarcza swoje destynacje, a :app składa je w jeden graf.

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

Trasy bezpieczne typowo

Nowoczesny Navigation Compose obsługuje trasy bezpieczne typowo: trasa jest obiektem @Serializable lub klasą danych, a nie magicznym ciągiem znaków. Każda funkcjonalność definiuje własny typ trasy w swoim module, dzięki czemu sama zarządza swoim kontraktem nawigacji.

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

@Serializable
data class ProfileRoute(val userId: String)

Funkcjonalności udostępniają rozszerzenia NavGraphBuilder

Najważniejszy mechanizm polega na tym, że każda funkcjonalność udostępnia funkcję rozszerzającą NavGraphBuilder, która rejestruje jej destynację. Funkcjonalność zarządza swoim ekranem, a :app tylko wywołuje tę funkcję. Funkcjonalność nigdy nie odwołuje się do innych funkcjonalności.

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

Rozdzielanie zależności za pomocą callbacków nawigacji

Funkcjonalność nigdy nie może bezpośrednio wywoływać navigate(SomeOtherFeatureRoute), ponieważ wymagałoby to zależności od innej funkcjonalności. Zamiast tego udostępnia callbacki lambda, takie jak onProfileClick. To moduł :app decyduje, dokąd faktycznie prowadzą.

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

Moduł :app łączy wszystko

Tylko moduł :app zna wszystkie trasy i łączy callbacki z rzeczywistą nawigacją. To jedyne miejsce, w którym powiązania są akceptowalne — jego zadaniem jest właśnie składanie całości.

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

Bezpieczne przekazywanie argumentów

Ponieważ trasy są klasami danych @Serializable, argumenty są sprawdzane pod kątem typów podczas kompilacji. Odczytasz je ponownie za pomocą toRoute() wewnątrz destynacji. Nie musisz już parsować ciągów znaków ani obawiać się awarii w czasie działania związanych z 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()

Udostępnianie typów tras przez moduł api

Czasami jedna funkcjonalność rzeczywiście musi nawigować do innej i potrzebuje typu jej trasy. Zamiast zależeć od całej funkcjonalności, udostępnij samą trasę w niewielkim module :feature:profile:api, zawierającym wyłącznie trasę @Serializable. Ciężki moduł :impl pozostaje prywatny.

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

Zagnieżdżona nawigacja w funkcjonalności

Funkcjonalność z kilkoma ekranami może udostępniać cały zagnieżdżony graf za pomocą navigation<T>. Funkcjonalność zarządza swoim wewnętrznym przepływem, a :app tylko podłącza graf w jednym punkcie wejścia.

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

Deep linki między modułami

Trasy bezpieczne typowo obsługują również deep linki. Funkcjonalność deklaruje wzorzec URI deep linku dla swojej destynacji, a NavHost modułu :app kieruje przychodzący link do właściwego ekranu funkcjonalności — bez konieczności importowania innej funkcjonalności.

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

Podsumowanie wzorca rozdzielania zależności

Zasady w skrócie są proste:

  • Każda funkcjonalność zarządza własnym typem trasy i rozszerzeniem NavGraphBuilder.
  • Funkcjonalności komunikują zamiary za pomocą callbacków lambda, a nie bezpośredniej nawigacji.
  • Tylko :app zna wszystkie funkcjonalności i łączy callbacki z rzeczywistymi trasami.
  • Jeśli trasę trzeba współdzielić, udostępnij ją za pomocą niewielkiego modułu :api.

Dzięki temu funkcjonalności pozostają niezależne, mogą korzystać z pamięci podręcznej kompilacji i nie tworzą cykli.

Szybkie sprawdzenie

W aplikacji wielomodułowej :feature:home musi przenieść użytkownika do ekranu w :feature:profile. Jaki jest najczystszy sposób na zachowanie niezależności tych funkcjonalności?

Podsumowanie: nawigacja między modułami

Nauczyłeś się łączyć funkcjonalności bez ich wzajemnego powiązania:

  • Pojedynczy NavHost znajduje się w cienkim module :app.
  • Każda funkcjonalność zarządza trasą @Serializable i rozszerzeniem NavGraphBuilder.
  • Funkcjonalności udostępniają callbacki zamiast bezpośrednio nawigować do innych funkcjonalności.
  • Trasę należy współdzielić wyłącznie za pośrednictwem niewielkiego modułu :api, gdy jest to naprawdę potrzebne; deep linki i zagnieżdżone grafy działają według tego samego wzorca.

To kończy temat architektury aplikacji wielomodułowej: możesz teraz dzielić, łączyć i nawigować po skalowalnej bazie kodu Android.

Bezpłatny start

Ucz się Kotlin dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
36
Lekcje
152

Często zadawane pytania

Czy lekcja „Nawigacja między modułami” jest bezpłatna?

Tak — pełny tekst „Nawigacja między modułami” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Android Academy, przejdź na CoddyKit PRO. Kurs Android Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Nawigacja między modułami”?

Łącz funkcje bez ścisłego powiązania Ćwiczysz Android Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Android Academy?

Nie wymagamy żadnego doświadczenia. Android Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Nawigacja między modułami”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Android Academy?

Tak. Każda lekcja Android Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Dlaczego warto stosować moduły
  2. Moduły funkcji i moduły podstawowe
  3. Zarządzanie zależnościami modułów
  4. Nawigacja między modułami
← Powrót do Android Academy