0Pricing
Android Academy · Lekcja

Zarządzanie zależnościami modułów

Utrzymuj czysty i acykliczny graf

Zarządzanie zależnościami modułów to bezpłatna lekcja Android Academy na CoddyKit. To lekcja 3 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.

Graf zależności

Każdy moduł deklaruje, od których innych modułów zależy. Razem tworzą one graf zależności. Zdrowy graf jest DAG (skierowanym grafem acyklicznym): zależności wskazują w jednym kierunku i nigdy nie tworzą pętli.

W tej lekcji nauczysz się przejrzyście deklarować zależności, wybierać właściwą konfigurację Gradle, współdzielić wersje i zapobiegać cyklom.

Deklarowanie zależności modułu

Zależność od innego modułu dodajesz za pomocą project(":path:to:module") wewnątrz bloku dependencies. Ścieżka odzwierciedla strukturę folderów i odpowiada temu, co zadeklarowano w settings.gradle.kts.

// feature/profile/build.gradle.kts
dependencies {
    implementation(project(":core:data"))
    implementation(project(":core:designsystem"))
    implementation(project(":core:model"))
}

implementation a api

Wybrana konfiguracja określa, co przenika do odbiorców:

  • implementation: zależność jest prywatna. Moduły zależne od Twojego modułu jej nie widzą. To ustawienie domyślne.
  • api: zależność jest ponownie udostępniana (tranzytywna). Używaj jej tylko wtedy, gdy Twoje publiczne typy pochodzą z tej zależności.

Niemal zawsze wybieraj implementation — poprawia to szybkość kompilacji, ponieważ zmiana ukrytej zależności nie zmusza odbiorców do ponownej kompilacji.

// core/data/build.gradle.kts
dependencies {
    // Repository signatures return :core:model types,
    // so consumers need to SEE it -> api
    api(project(":core:model"))

    // Network is an internal detail -> implementation
    implementation(project(":core:network"))
}

Dlaczego implementation przyspiesza kompilację

W przypadku implementation Gradle wie, że zmiana ukrytej zależności nie może wpłynąć na publiczne ABI modułu. Odbiorcy nie muszą więc ponownie się kompilować. W przypadku api zmiana propaguje się do każdego tranzytywnego odbiorcy.

Praktyczna zasada: zależność umieszczaj w api tylko wtedy, gdy występuje w publicznych typach modułu (typach zwracanych lub publicznych parametrach). W przeciwnym razie użyj implementation.

// Public -> needs api
fun observeUser(): Flow<User>   // Flow and User leak out

// Internal -> implementation is enough
private val client: OkHttpClient // never exposed

Centralizowanie wersji: katalog wersji

W przypadku wielu modułów nie chcesz powtarzać wersji bibliotek w każdym miejscu. Katalog wersji Gradle (gradle/libs.versions.toml) definiuje wersje i aliasy w jednym miejscu. Każdy moduł odwołuje się do tego samego aliasu.

# gradle/libs.versions.toml
[versions]
compose-bom = "2024.09.00"
retrofit = "2.11.0"

[libraries]
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }

Korzystanie z katalogu w module

Moduły odwołują się następnie do bibliotek za pomocą wygenerowanego akcesora libs. Brak numerów wersji w pliku kompilacji oznacza, że aktualizacje wykonuje się w jednym miejscu.

// core/network/build.gradle.kts
dependencies {
    implementation(platform(libs.compose.bom))
    implementation(libs.retrofit)
}

Grzech śmiertelny: cykle

Cykl występuje wtedy, gdy moduł A zależy od B, a B z powrotem od A (bezpośrednio lub przez łańcuch zależności). Gradle odmawia kompilacji w przypadku zależności cyklicznej. Jest to również sygnał problemu projektowego: granica między tymi modułami została wyznaczona niewłaściwie.

// :feature:cart  -> implementation(project(":feature:checkout"))
// :feature:checkout -> implementation(project(":feature:cart"))
//
// Gradle error:
// Circular dependency between the following tasks:
// :feature:cart:compile -> :feature:checkout:compile -> :feature:cart:compile

Przerywanie cyklu

Aby przerwać cykl, wyodrębnij wspólny fragment do niższego modułu, od którego oba moduły będą mogły zależeć. Jeśli dwie funkcjonalności potrzebują wzajemnie swoich danych, wspólny kontrakt powinien znajdować się w core, a nie w żadnej z tych funkcjonalności.

Przywraca to przepływ w dół: obie funkcjonalności wskazują na core, a core nigdy nie wskazuje z powrotem w górę.

// Before: cart <-> checkout (cycle)
// After:  cart -> :core:order  <-  checkout

// core/order/OrderContract.kt
data class Order(val items: List<CartItem>, val total: Double)

// feature/cart    -> implementation(project(":core:order"))
// feature/checkout-> implementation(project(":core:order"))

Odwrócenie zależności: zależność od abstrakcji

Czasami moduł niskiego poziomu potrzebuje zachowania, które znajduje się wyżej. Zamiast tworzyć zależność skierowaną w górę, zdefiniuj interfejs w module niższego poziomu i pozwól modułowi wyższego poziomu dostarczyć implementację za pomocą wstrzykiwania zależności. To właśnie odwrócenie zależności.

// core/analytics defines the contract
interface AnalyticsLogger {
    fun log(event: String)
}

// :app provides the real implementation and injects it down
@Module
@InstallIn(SingletonComponent::class)
object AnalyticsModule {
    @Provides
    fun logger(impl: FirebaseAnalyticsLogger): AnalyticsLogger = impl
}

Wizualizacja i ochrona grafu

Możesz poprosić Gradle o wyświetlenie lub wyrenderowanie grafu modułów, a nawet dodać test, który przerwie kompilację, jeśli pojawi się niedozwolona zależność (na przykład moduł core zależny od funkcjonalności). Narzędzia takie jak wtyczka module-graph automatycznie generują diagram.

# Print the project structure
./gradlew projects

# Inspect why :feature:home pulls in a library
./gradlew :feature:home:dependencies --configuration debugRuntimeClasspath

Przejrzysty, acykliczny przykład

Oto zdrowy graf. Czytaj go od góry do dołu; żadna strzałka nie wskazuje z powrotem w górę i żadne dwa moduły nie wskazują na siebie nawzajem. Właśnie do tego należy dążyć.

// :app
//   -> :feature:home   -> :core:data -> :core:network -> :core:model
//   -> :feature:profile -> :core:data -> :core:database -> :core:model
//   -> :core:designsystem
//
// Every path ends at :core:model. No cycles. Builds in parallel.

Szybkie sprawdzenie

Moduł :core:network korzysta z OkHttpClient tylko wewnętrznie — ten typ nigdy nie pojawia się w sygnaturze publicznej funkcji. Której konfiguracji Gradle należy użyć do zadeklarowania zależności OkHttp?

Podsumowanie: zarządzanie zależnościami modułów

Nauczyłeś się utrzymywać zdrowy graf modułów:

  • Deklaruj zależności modułów za pomocą project(":path").
  • Domyślnie używaj implementation; api stosuj tylko w przypadku typów należących do publicznego interfejsu modułu.
  • Centralizuj wersje w katalogu wersji (libs.versions.toml).
  • Nigdy nie twórz cykli — Gradle je odrzuca; przerywaj je, przenosząc wspólny kod niżej lub odwracając zależności za pomocą interfejsów.

W następnej części połączysz funkcjonalności za pomocą nawigacji, bez ich wzajemnego powiązania.

Często zadawane pytania

Czy lekcja „Zarządzanie zależnościami modułów” jest bezpłatna?

Tak — pełny tekst „Zarządzanie zależnościami modułów” 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 „Zarządzanie zależnościami modułów”?

Utrzymuj czysty i acykliczny graf Ć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 3 z 4.

Ile czasu zajmuje lekcja „Zarządzanie zależnościami modułów”?

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