Luând în considerare modularizarea proiectelor Android

Publicat: 2019-08-21

Când un proiect atinge o anumită scară, atunci lucrarea ulterioară cu el într-un singur modul devine mai puțin eficientă. Modularizarea acestuia devine apoi o soluție eficientă.

4 avantaje ale modularizării

Înainte de a decide asupra modularizării, este bine să fiți clar ce este implicat. Avantajele unei structuri de proiect Android modulare includ:

O mai bună izolare a codului

Fiecare modul își poate expune interfețele publice API și poate ascunde detaliile de implementare. Cu un singur modul, nu poți fi complet sigur că implementarea lui este bine ascunsă (mai ales în Kotlin, unde un modificator de vizibilitate a pachetului nu este disponibil).

Evaluare mai ușoară a noilor tehnologii

Când creați un modul, puteți verifica noul model de arhitectură sau noua bibliotecă fără a afecta celelalte module.

Reducerea timpului de construire a proiectului

Modificarea unui modul necesită reconstruirea acelui modul și a altora care depind de el. Vedeți exact cum funcționează citind această documentație: Dezvoltatori Android. Configurații de dependență

Lucru mai convenabil

Devine mai ușor de analizat/depanat/refactorizat bucăți de cod mai mici și izolate. De asemenea, integrarea noilor dezvoltatori va merge mai rapid.

Aceste beneficii sună suficient pentru a vă convinge să începeți procesul de modularizare, dar cum începeți?

#1: Identificați-vă modulele și relațiile lor

Există două abordări pentru a vă recunoaște modulele: după caracteristică și după strat.

În modulele de caracteristici, puteți înțelege anumite zone ale aplicației disponibile utilizatorilor (de exemplu, autentificare, tablou de bord, profil etc.). Aceste zone pot consta dintr-un singur ecran sau un flux de ecrane care acoperă un anumit proces. Modulele de acest tip nu pot depinde de modulele de același tip.

După identificarea caracteristicilor, cu siguranță va trebui să extrageți funcționalitățile comune necesare pentru câteva sau chiar toate modulele. Aceste module pot fi responsabile pentru straturi separate de arhitectură (cum ar fi stocarea persistentă, rețeaua, navigarea, componentele UI...) sau logica de afaceri a procesării unor date utilizate de un set de caracteristici. Aceste tipuri de module sunt de obicei numite biblioteci . Modulele bibliotecii pot construi arbori de dependență.

Pe lângă modulele de caracteristici și bibliotecă, există și necesitatea unui modul pentru a gestiona conexiunile orizontale între alte module (mai multe despre acest lucru în punctul următor). Acest modul va conține o clasă de aplicație personalizată și o configurație de injectare a dependenței. Niciun alt modul nu poate depinde de acest modul, dar acest modul depinde de toate celelalte din proiect.

Modulele și relațiile lor în aplicații

Luând în considerare definițiile de mai sus, ierarhia modulelor poate arăta astfel:

#2: Configurarea injecției de dependență

În ciuda dependențelor dintre modulele de proiect, ar trebui să configurați și dependențe de pumnal. Dagger oferă două moduri de declarare a dependenței: subcomponente și dependență de componente .

Dependența subcomponenta Pumnal necesită ca părinții să declare toți copiii aflați în întreținere. Între modulele de proiect, acest tip de relație nu ar funcționa, deoarece inversează direcția dependenței de modulul de proiect. Dar poate fi folosit în module de proiect separate.

Dependența componentei pumnal este mai flexibilă, deoarece un copil poate declara că este dependent de părinte. Acest lucru face posibilă utilizarea acestui tip de dependență între modulele de proiect separate.

La un moment dat, este posibil să descoperiți că un modul are nevoie de cunoștințe limitate despre alt modul. Un exemplu foarte bun în acest sens poate fi navigarea între modulele de caracteristici. Furnizarea acestui tip de relație este adesea numită dependență orizontală . Pentru a crea acest canal de comunicare între module separate sunt necesare module suplimentare cu interfețe care descriu această comunicare și modul care va lega o implementare la interfețele declarate.

Configurarea dependenței modulului de proiect pentru a gestiona dependența orizontală este prezentată în imaginea de mai jos:

Configurarea dependenței modulului de proiect

Exemplu de cod pentru astfel de relații este furnizat într-un proiect la sfârșitul articolului.

#3: Configurarea Gradle

Fiecare modul de proiect are gradle.build-ul său, care este aproape același, cu excepția dependențelor adăugate și a pluginurilor. Prin urmare, este plăcut să extrageți configurația repetitivă într-un fișier gradle la rădăcina directorului de proiect. Un astfel de fișier poate înregistra, de asemenea, sarcini gradle obișnuite pentru a executa analiza codului static sau a rula testarea unitară.

Fragment de cod al unei astfel de configurații comune se găsește aici:

 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) } } }

Concluzie

Acest articol nu este exhaustiv sau un ghid complet pentru modularizarea unui proiect Android. Dar cred că abordează aspecte pe care ar trebui să le luați în considerare atunci când începeți modularizarea proiectului.

O bucată de cod pentru a prezenta o dependență orizontală se găsește la link.

Doriți să construiți o aplicație nativă pentru Android? Alege Miquido!