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 exposedCentralizowanie 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:compilePrzerywanie 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 debugRuntimeClasspathPrzejrzysty, 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;apistosuj 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
- Dlaczego warto stosować moduły
- Moduły funkcji i moduły podstawowe
- Zarządzanie zależnościami modułów
- Nawigacja między modułami