Biorąc pod uwagę modularyzację projektu Android
Opublikowany: 2019-08-21Kiedy projekt osiągnie określoną skalę, dalsza praca z nim w jednym module staje się mniej efektywna. Modularyzacja staje się wtedy skutecznym rozwiązaniem.
4 zalety modularyzacji
Przed podjęciem decyzji o modularyzacji dobrze jest dokładnie określić, o co chodzi. Do zalet modułowej struktury projektu androida należą:
Lepsza izolacja kodu
Każdy moduł może ujawnić swoje publiczne interfejsy API i ukryć szczegóły implementacji. Przy pojedynczym module nie można mieć całkowitej pewności, że jego implementacja jest dobrze ukryta (zwłaszcza w Kotlinie, gdzie modyfikator widoczności pakietu nie jest dostępny).
Łatwiejsza ocena nowych technologii
Kiedy tworzysz moduł, możesz sprawdzić nowy wzorzec architektury lub nową bibliotekę bez wpływu na inne moduły.
Skrócony czas budowy projektu
Modyfikowanie modułu wymaga przebudowania tego modułu i innych, które są od niego zależne. Zobacz dokładnie, jak to działa, czytając tę dokumentację: Programiści Androida. Konfiguracje zależności
Wygodniejsza praca
Łatwiej jest analizować/debugować/refaktoryzować mniejsze i izolowane fragmenty kodu. Ponadto wdrażanie nowych programistów będzie przebiegać szybciej.
Te korzyści brzmią wystarczająco, aby przekonać Cię do rozpoczęcia procesu modularyzacji, ale jak zacząć?
#1: Zidentyfikuj swoje moduły i ich relacje
Istnieją dwa podejścia do rozpoznawania modułów: według funkcji i według warstwy.
W ramach modułów funkcji możesz zrozumieć niektóre obszary aplikacji dostępne dla użytkowników (np. login, pulpit nawigacyjny, profil itp.). Obszary te mogą składać się z pojedynczego ekranu lub szeregu ekranów obejmujących pewien proces. Moduły tego typu nie mogą zależeć od modułów tego samego typu.
Po zidentyfikowaniu cech, na pewno będziesz musiał wyodrębnić wspólne funkcjonalności wymagane przez kilka lub nawet wszystkie moduły. Moduły te mogą odpowiadać za oddzielne warstwy architektury (takie jak trwałe przechowywanie, sieć, nawigacja, komponenty UI…) lub logikę biznesową przetwarzania niektórych danych wykorzystywanych przez zestaw funkcji. Tego rodzaju moduły są zwykle nazywane bibliotekami . Moduły biblioteczne mogą budować drzewa zależności.
Oprócz modułów fabularnych i bibliotecznych istnieje również potrzeba jednego modułu do zarządzania połączeniami poziomymi między innymi modułami (więcej o tym w następnym punkcie). Ten moduł będzie zawierał niestandardową klasę aplikacji i konfigurację wstrzykiwania zależności. Żaden inny moduł nie może zależeć od tego modułu, ale ten moduł zależy od wszystkich innych w projekcie.

Biorąc pod uwagę powyższe definicje hierarchia modułów może wyglądać tak:
#2: Konfiguracja wstrzykiwania zależności
Pomimo zależności między modułami projektu, powinieneś również ustawić zależności sztyletowe. Dagger oferuje dwa sposoby deklarowania zależności: subcomponents i component dependency .
Zależność podkomponentu sztyletu wymaga, aby rodzice zadeklarowali wszystkie zależne dzieci. Pomiędzy modułami projektu ten rodzaj relacji nie zadziałałby, ponieważ odwraca kierunek zależności modułu projektu. Ale może być używany w osobnych modułach projektu.
Zależność komponentu Dagger jest bardziej elastyczna, ponieważ dziecko może zadeklarować, że jest zależne od rodzica. Umożliwia to wykorzystanie tego rodzaju zależności pomiędzy oddzielnymi modułami projektu.

W pewnym momencie może się okazać, że jeden moduł wymaga ograniczonej wiedzy na temat innego modułu. Bardzo dobrym przykładem może być nawigacja między modułami funkcji. Zapewnienie tego rodzaju relacji jest często nazywane zależnością poziomą . Do stworzenia tego kanału komunikacyjnego pomiędzy oddzielnymi modułami potrzebne są dodatkowe moduły z interfejsami opisującymi tę komunikację oraz moduł, który powiąże implementację z zadeklarowanymi interfejsami.
Konfiguracja zależności modułu projektu do zarządzania zależnościami poziomymi jest przedstawiona na poniższym obrazku:

Przykładowy kod dla takich relacji znajduje się w projekcie na końcu artykułu.
#3: Konfiguracja Gradle
Każdy moduł projektu ma swój gradle.build, który jest prawie taki sam, z wyjątkiem dodanych zależności i wtyczek. Tak więc fajnie jest wyodrębnić powtarzalną konfigurację do jednego pliku gradle w katalogu głównym katalogu projektu. Taki plik może również rejestrować typowe zadania Gradle w celu wykonania statycznej analizy kodu lub uruchomienia testów jednostkowych.
Fragment kodu takiej wspólnej konfiguracji można znaleźć tutaj:
afterEvaluate { project -> def isAndroid = project.plugins.hasPlugin('com.android.library') || project.plugins.hasPlugin('com.android.application') setupModule(isAndroid) setupCommonTestDependencies(isAndroid) setupCommonTasks(isAndroid) } def setupModule(isAndroid) { if (isAndroid) { android { compileSdkVersion projectCompileSdk defaultConfig { minSdkVersion projectMinSdk targetSdkVersion projectTargetSdk } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } lintOptions { abortOnError true checkReleaseBuilds false checkAllWarnings true warningsAsErrors true def lintBaseline = file("quality/lint-baseline.xml") if (lintBaseline.exists()) baseline lintBaseline } } } else { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } } def setupCommonTestDependencies(isAndroid) { dependencies { testImplementation "junit:junit:${junitVersion}" testImplementation "org.assertj:assertj-core:${assertJVersion}" testImplementation "org.mockito:mockito-core:${mockitoVersion}" testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:${mockitoKotlinVersion}" if (isAndroid) { androidTestImplementation "androidx.test.ext:junit:${axTestJUnitVersion}" androidTestImplementation "androidx.test.espresso:espresso-core:${axEspressoLibVersion}" } } } def setupCommonTasks(isAndroid) { if (isAndroid) { tasks.register("unitTest") { task -> task.dependsOn(testDebugUnitTest) } } else { tasks.register("unitTest") { task -> task.dependsOn(test) } } }
Wniosek
Ten artykuł nie jest wyczerpujący ani nie jest kompletnym przewodnikiem dotyczącym modularyzacji projektu Androida. Myślę jednak, że porusza aspekty, które należy wziąć pod uwagę, rozpoczynając modularyzację projektu.
Fragment kodu prezentujący poziomą zależność można znaleźć pod linkiem.
Chcesz zbudować natywną aplikację na Androida? Wybierz Miquido!