Prinzipien zum Erstellen von Android-Anwendungen mit mehreren Modulen / Sudo Null IT News

Dieser Artikel ist eine Übersetzung des kürzlich von Google veröffentlichten Leitfadens zur Modularisierung von Android-Anwendungen.

Beginnen wir mit der Tatsache, dass es keine einzelne Strategie zum Erstellen von Anwendungen mit mehreren Modulen gibt, die für alle Projekte geeignet ist. Es hängt alles von den Aufgaben ab, die Sie lösen, und vom Projekt. Mit Hilfe des Gradle-Build-Systems können Sie ein Projekt mit mehreren Modulen flexibel organisieren. Daher werden wir uns in diesem Artikel mit allgemeinen Regeln und Mustern befassen, die bei der Entwicklung der meisten Android-Anwendungen mit mehreren Modulen verwendet werden können.

Prinzipien der hohen Kohäsion und losen Kopplung

Der in Module unterteilte Code zeichnet sich durch die Eigenschaften der Verschränkung und Kohäsion aus. Die Konnektivitätseigenschaft zeigt, wie Module voneinander abhängen. Verschränkung kennzeichnet, wie ähnlich die Elemente in einem Modul funktional sind. Als allgemeine Regel sollte man eine hohe Verschränkung und eine geringe Kopplung anstreben.

Lose Kopplung bedeutet, dass Module so unabhängig wie möglich voneinander sein sollten, damit Änderungen in einem Modul andere Module nicht beeinflussen. Module müssen nichts über die interne Implementierung anderer Module wissen.

Hohe Kohäsion impliziert, dass Module Komponenten enthalten müssen, die als System funktionieren. Jede Komponente sollte ihre eigene klare Verantwortung und Domäne, Fachgebiet haben. Betrachten Sie eine E-Book-Reader-App. Es ist nicht die beste Idee, den Code, der für das Lesen eines Buches und das Bezahlen verantwortlich ist, in einem Modul zu verknüpfen, da dies 2 verschiedene Funktionsdomänen sind.

Tipp: Wenn die Arbeit zweier Module von der Funktionalität jedes von ihnen abhängt, ist dies wahrscheinlich ein Zeichen dafür, dass sie als ein einziges System innerhalb desselben Moduls funktionieren sollten. Wenn umgekehrt die Komponenten innerhalb desselben Moduls nicht miteinander interagieren, sollten sie vielleicht in verschiedene Module aufgeteilt werden.

Modultypen

Die Art und Weise, wie Sie Module organisieren, hängt hauptsächlich von der Architektur Ihrer Anwendung ab. Im Folgenden finden Sie einige gängige Beispiele für Module, die Sie Ihrer Anwendung hinzufügen können, indem Sie die empfohlenen befolgen Android-Anwendungsarchitektur.

Datenmodule (Datenmodule).

Ein Datenmodul enthält normalerweise ein Repository, Datenquellen und Modellklassen. Die drei Hauptaufgaben des Datenmoduls sind:

  1. Kapselung, Verbergen von Daten und Geschäftslogik für einen bestimmten Themenbereich, eine Domäne. Jedes Datenmodul ist für die Verarbeitung und Arbeit mit Daten verantwortlich, die eine bestimmte Domäne, einen bestimmten Themenbereich darstellen. Es kann viele Arten von Daten verarbeiten, solange sie zusammenhängen.

  2. Stellen Sie das Repository als externe API bereit. Die öffentliche API des Datenmoduls sollte ein Repository sein, da es für die Bereitstellung von Daten für den Rest der Anwendung verantwortlich ist.

  3. Zugriff auf Implementierungsdetails und Datenquelle ausblenden: Auf Datenquellen sollte nur von Repositories aus demselben Modul zugegriffen werden können. Sie bleiben dem Zugriff von außen verborgen. Sie können dies bereitstellen, indem Sie das private oder interne Sichtbarkeitsschlüsselwort verwenden.

Abbildung 1. Ein Beispiel für Datenmodule und ihre Struktur.  Feature-Module sind orange hervorgehoben und werden weiter unten besprochen.Abbildung 1. Ein Beispiel für Datenmodule und ihre Struktur. Feature-Module sind orange hervorgehoben und werden weiter unten besprochen.

Funktionsmodule. funktionale Module.

Eine Funktion ist eine isolierte Anwendungsfunktionalität, die normalerweise einem Bildschirm oder einer Reihe eng verwandter Bildschirme entspricht, z. B. dem Registrierungs- oder Bestellvorgang. Wenn Ihre App über eine untere Leiste für die Navigation verfügt, ist es wahrscheinlich, dass jedes Ziel eine separate Funktion ist.

Jede Registerkarte kann eine separate Funktion sein.Jede Registerkarte kann eine separate Funktion sein.

Funktionen sind Bildschirmen oder Zielen in Ihrer Anwendung zugeordnet. Sie verfügen höchstwahrscheinlich über eine zugeordnete Benutzeroberfläche und ein ViewModel, um ihre Logik und ihren Zustand zu handhaben. Ein Beispiel wäre die Zahlungsfunktionalität, Benutzerautorisierung. Die Funktionalität muss nicht auf einen einzelnen Bildschirm oder eine Navigationsposition beschränkt sein. Feature-Module hängen von Datenmodulen ab.

Ein Beispiel für Feature-Module und deren Struktur.  Solche Module hängen von Datenmodulen ab.Ein Beispiel für Feature-Module und deren Struktur. Solche Module hängen von Datenmodulen ab.

App-Module. Anwendungsmodule.

App-Module sind der Einstiegspunkt in die Anwendung. Sie hängen von Feature-Modulen ab und bieten normalerweise Root-Navigation. Ein Anwendungsmodul kann aufgrund von Unterschieden in mehrere verschiedene Binärdateien kompiliert werden Variante bauen.

Abhängigkeitsdiagramm für Demo- und Vollversion der Anwendung, abhängig von der ausgewählten Build-OptionAbhängigkeitsdiagramm für Demo- und Vollversion der Anwendung, abhängig von der ausgewählten Build-Option

Wenn Ihre App auf mehrere Gerätetypen wie Android Auto, Android Wear oder Android TV ausgerichtet ist, können Sie App-Module für jedes Gerät trennen. Dies hilft, plattformspezifische Abhängigkeiten zu trennen.

Abhängigkeitsdiagramm für die Android Auto AppAbhängigkeitsdiagramm für die Android Auto App

Gemeinsame Module. Allgemeine Module.

Freigegebene Module, auch Kernmodule genannt, enthalten Code, der häufig von anderen Modulen verwendet wird. Sie reduzieren die Redundanz und stellen keine bestimmte Schicht in der Architektur der Anwendung dar. Im Folgenden finden Sie Beispiele für gängige Module:

  • UI-Modul. Wenn Sie über benutzerdefinierte UI-Komponenten oder komplexes Branding verfügen, können Sie UI-Widgets zur späteren Wiederverwendung in ein separates Modul unterteilen. Dadurch wird die Benutzeroberfläche Ihrer Anwendung konsistent. Wenn Ihre Benutzeroberfläche in ein separates Modul unterteilt ist, können Sie außerdem ein mühsames Refactoring beim Rebranding vermeiden.

  • Analysemodul: Die Verfolgung verschiedener Ereignisse wird oft von Geschäftsanforderungen ohne Rücksicht auf die Softwarearchitektur vorgegeben. Analytics-Tracker werden häufig in vielen unabhängigen Komponenten verwendet. In diesem Fall wäre es schön, ein dediziertes Analysemodul zu haben.

  • Netzwerkmodul: Wenn viele Module eine Netzwerkverbindung erfordern, sollten Sie erwägen, ein Modul zu erstellen, das ausschließlich der Bereitstellung eines HTTP-Clients dient. Dies ist besonders nützlich, wenn Ihr Client eine benutzerdefinierte Konfiguration benötigt.

  • Dienstprogramm, Servicemodul: Dienstprogramme, verschiedene Helfer, sind normalerweise kleine Codestücke, die in einer Anwendung wiederverwendet werden. Beispiele für Dienstprogramme sind Testklassen, ein Währungsformatierer und ein E-Mail-Validierer.

Interaktion zwischen Modulen.

Module existieren selten vollständig separat und hängen oft von anderen Modulen ab und interagieren mit ihnen. Es ist wichtig, eine niedrige Kopplung aufrechtzuerhalten, selbst wenn Module zusammenarbeiten und häufig Informationen austauschen. Manchmal ist eine direkte Verknüpfung zwischen zwei Modulen aufgrund architektonischer Einschränkungen oder zirkulärer Abhängigkeiten unerwünscht.

Eine direkte bidirektionale Kommunikation zwischen Modulen ist aufgrund von zirkulären Abhängigkeiten nicht möglich.  Ein Zwischenmodul wird benötigt, um den Datenfluss zwischen zwei anderen unabhängigen Modulen zu koordinieren.Eine direkte bidirektionale Kommunikation zwischen Modulen ist aufgrund von zirkulären Abhängigkeiten nicht möglich. Ein Zwischenmodul wird benötigt, um den Datenfluss zwischen zwei anderen unabhängigen Modulen zu koordinieren.

Um dieses Problem zu lösen, können Sie ein drittes Modul haben, das zwischen den beiden anderen Modulen vermittelt. Das Proxy-Modul kann Nachrichten von beiden Modulen abhören und sie nach Bedarf weiterleiten. In unserer Beispielanwendung muss der Checkout-Bildschirm wissen, welches Buch gekauft werden soll, auch wenn das Ereignis auf einem separaten Bildschirm ausgelöst wird, der Teil einer anderen Funktion ist. In diesem Fall ist der Proxy das Modul, dem der Navigationsgraph gehört (normalerweise das Anwendungsmodul). In diesem Beispiel verwenden wir die Navigation, um mithilfe der Navigationskomponente Daten vom Home-Feature-Modul an das Checkout-Feature-Modul zu übergeben.

navController.navigate(“checkout/$bookId”)

Wenn Sie die ID des Buchs als Argument verwenden, können Sie vollständige Informationen über das Buch erhalten.

class CheckoutViewModel(savedStateHandle: SavedStateHandle, …) : ViewModel() { val uiState: StateFlow = savedStateHandle.getStateFlow(“bookId”, “”).map { bookId -> // UI-Status erzeugen, der bookRepository aufruft. getBook(bookId) } … }

Sie sollten keine Objekte als Navigationsargumente übergeben. Verwenden Sie stattdessen einfache Bezeichner, über die Daten mithilfe der Datenschicht geladen werden können. Auf diese Weise halten Sie eine geringe Kopplung aufrecht und verletzen nicht das Single-Source-of-Truth-Prinzip.

Im Beispiel unten hängen beide Feature-Module vom selben Datenmodul (data:books) ab. Dies minimiert die Datenmenge, die das Proxy-Modul senden muss, und hält die Kommunikation zwischen den Modulen gering. Anstatt Objekte zu übergeben, sollten Module primitive IDs austauschen und Ressourcen von einem gemeinsam genutzten Datenmodul laden.

Zwei Funktionsmodule, die ein gemeinsames Datenmodul zum Empfangen von Daten verwenden.Zwei Funktionsmodule, die ein gemeinsames Datenmodul zum Empfangen von Daten verwenden.

Generelle Empfehlungen

Wie eingangs erwähnt, gibt es keinen einzig richtigen Weg, um eine Anwendung mit mehreren Modulen zu entwickeln. So wie es viele Softwarearchitekturen gibt, gibt es viele Möglichkeiten, eine Anwendung zu modularisieren. Die folgenden allgemeinen Richtlinien helfen Ihnen jedoch dabei, Ihren Code besser lesbar, wartbar und testbar zu machen.

Pflegen Sie eine konsistente Konfiguration

Jedes Modul führt zusätzlichen Overhead zum Einrichten der Modulkonfiguration ein. Wenn die Anzahl Ihrer Module einen bestimmten Schwellenwert erreicht, wird das Konfigurationsmanagement zum Problem. Beispielsweise ist es wichtig, dass Module Abhängigkeiten von Bibliotheken derselben Version verwenden. Wenn Sie eine große Anzahl von Modulen aktualisieren müssen, nur um eine Bibliotheksversion zu erstellen, ist dies nicht nur zusätzlicher Zeit- und Arbeitsaufwand, sondern auch ein Ort für potenzielle Fehler. Um dieses Problem zu lösen, können Sie eines der einzelnen Gradle-Tools für die Konfiguration verwenden:

Minimieren Sie die öffentliche API

Die öffentliche Schnittstelle des Moduls sollte minimal sein und nur das Wesentliche anzeigen. Einzelheiten der Umsetzung sollten nicht veröffentlicht werden. Verwenden Sie die privaten oder internen Modifikatoren, um den Bereich zu reduzieren, um Methoden oder Eigenschaften für das Modul privat zu machen. Wenn Sie Abhängigkeiten in Ihrem Modul deklarieren, bevorzugen Sie die Verbindung über die Implementierung und nicht über die API. Letzteres stellt den Verbrauchern Ihres Moduls transitive Abhängigkeiten bereit. Die Verwendung der Implementierung kann die Erstellungszeit verkürzen, da die Anzahl der Module reduziert wird, die nach Änderungen neu erstellt werden müssen.

Bevorzugen Sie Kotlin- und Java-Module gegenüber Android-Modulen.

Android Studio unterstützt drei Haupttypen von Modulen:

  • App-Module, Anwendungsmodule sind der Einstiegspunkt zu Ihrer Anwendung. Sie können Quellcode, Ressourcen, eine Aktivität und eine AndroidManifest.xml-Datei enthalten. Das Ergebnis eines App-Moduls ist ein Android-App-Artefakt (AAB oder APK).

  • Bibliotheksmodule denselben Inhalt haben wie App-Module. Sie werden von anderen Android-Modulen als Abhängigkeit verwendet. Die Ausgabe eines Bibliotheksmoduls ist ein Android-Archiv (AAR), das strukturell mit Anwendungsmodulen identisch ist, aber in ein AAR kompiliert wird, das später von anderen Modulen als Abhängigkeit verwendet werden kann. Das Bibliotheksmodul ermöglicht es Ihnen, dieselbe Logik und dieselben Ressourcen in vielen App-Modulen zu kapseln und wiederzuverwenden.

  • Kotlin- und Java-Module enthalten keine Android-Ressourcen, Aktivitäten oder Android-Manifestdateien. Wenn Ihr Modul keine Abhängigkeit vom Android SDK hat, sollten Sie vorzugsweise Kotlin oder ein Java-Modul verwenden.

Vergessen Sie nicht, sich uns anzuschließen Telegrammund auf der Plattform AndroidSchool.ru nützliche Materialien für den Android-Entwickler und moderne Tutorials werden veröffentlicht.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *