Auf dieser Seite werden mehrere Best Practices und Empfehlungen für die Architektur vorgestellt. Nimm sie an, um die Qualität, Stabilität und Skalierbarkeit deiner App zu verbessern. Außerdem die Wartung und das Testen Ihrer App erleichtern.
Die folgenden Best Practices sind nach Themen gruppiert. Jedes hat eine Priorität, die wie stark das Team sie empfiehlt. Die Prioritätenliste sieht so aus:
- Dringende Empfehlung:Sie sollten diese Vorgehensweise implementieren, es sei denn, es besteht ein Konflikt Ihre Herangehensweise.
- Empfohlen:Durch diese Vorgehensweise wird Ihre App wahrscheinlich verbessert.
- Optional:Durch diese Vorgehensweise kann Ihre App unter bestimmten Umständen verbessert werden.
Mehrschichtige Architektur
Unsere empfohlene mehrstufige Architektur bevorzugt die Trennung von Belangen. Es unterstützt die Benutzeroberfläche aus Datenmodellen, entspricht dem Prinzip der Single Source of Truth, und folgt den Prinzipien des unidirektionalen Datenflusses. Hier sind einige der besten mehrschichtige Architektur:
Empfehlung | Beschreibung |
---|---|
Verwenden Sie eine klar definierte Datenschicht.
Dringend empfohlen |
Über die Datenschicht sind die Anwendungsdaten für den Rest der App verfügbar und sie enthält den Großteil der Geschäftslogik der App.
<ph type="x-smartling-placeholder">
|
Verwenden Sie eine klar definierte UI-Ebene.
Dringend empfohlen |
Die UI-Ebene stellt die Anwendungsdaten auf dem Bildschirm dar und dient als primärer Punkt der Nutzerinteraktion.
|
Die Datenschicht sollte Anwendungsdaten über ein Repository verfügbar machen.
Dringend empfohlen |
Komponenten auf der UI-Ebene wie zusammensetzbare Funktionen, Aktivitäten oder ViewModels dürfen nicht direkt mit einer Datenquelle interagieren. Beispiele für Datenquellen:
|
Koroutinen und Abläufe verwenden.
Dringend empfohlen |
Verwenden Sie Koroutinen und Abläufe, um zwischen Ebenen zu kommunizieren. |
Verwenden Sie eine Domainebene.
Empfohlen in großen Apps |
Verwenden Sie eine Domainebene, wenn Sie die Geschäftslogik in mehreren ViewModels wiederverwenden oder die Geschäftslogik eines bestimmten ViewModel vereinfachen möchten. |
UI-Ebene
Die UI-Ebene hat die Aufgabe, die Anwendungsdaten auf dem Bildschirm darzustellen. und dienen als primärer Punkt der Nutzerinteraktion. Hier sind einige Best Practices, für die UI-Ebene:
Empfehlung | Beschreibung |
---|---|
Folgen Sie der Anleitung unter Unidirektionaler Datenfluss (UDF).
Dringend empfohlen |
Befolgen Sie die Prinzipien des unidirektionalen Datenflusses (UDF), wobei ViewModels den Status der Benutzeroberfläche mithilfe des Beobachtermusters verfügbar machen und durch Methodenaufrufe Aktionen von der Benutzeroberfläche empfangen. |
Verwenden Sie AAC ViewModels, wenn sich deren Vorteile auf Ihre App auswirken.
Dringend empfohlen |
Verwenden Sie AAC ViewModels zur Verarbeitung der Geschäftslogik und rufen Sie Anwendungsdaten ab, um den UI-Status der Benutzeroberfläche (Compose oder Android Views) anzuzeigen.
Weitere Best Practices für ViewModel Weitere Informationen zu den Vorteilen von ViewModels |
Verwenden Sie die lebenszyklusorientierte Erfassung des UI-Status.
Dringend empfohlen |
Sie können den UI-Status mit dem entsprechenden Builder für Lifecycle-Events über die UI erfassen: repeatOnLifecycle im View-System und collectAsStateWithLifecycle in Jetpack Compose.
Weitere Informationen zu Weitere Informationen zu |
Senden Sie keine Ereignisse von ViewModel an die Benutzeroberfläche.
Dringend empfohlen |
Verarbeitet das Ereignis sofort in ViewModel und führt zu einer Statusaktualisierung mit dem Ergebnis der Verarbeitung des Ereignisses. Weitere Informationen zu UI-Ereignissen |
Verwenden Sie eine Anwendung mit nur einer Aktivität.
Empfohlen |
Verwenden Sie Navigationsfragmente oder Navigationseditor, um zwischen Bildschirmen zu wechseln und einen Deeplink zu Ihrer App zu erstellen, wenn Ihre App mehr als einen Bildschirm hat. |
Verwenden Sie Jetpack Compose.
Empfohlen |
Mit Jetpack Compose lassen sich neue Apps für Smartphones, Tablets, faltbare Geräte und Wear OS entwickeln. |
Das folgende Snippet veranschaulicht, wie Sie den UI-Status in einem Art und Weise:
Aufrufe
class MyFragment : Fragment() {
private val viewModel: MyViewModel by viewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect {
// Process item
}
}
}
}
}
Schreiben
@Composable
fun MyScreen(
viewModel: MyViewModel = viewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}
ViewModel
ViewModels sind für die Bereitstellung des UI-Status und des Zugriffs auf die der Datenschicht. Hier sind einige Best Practices für ViewModels:
Empfehlung | Beschreibung |
---|---|
ViewModels sollte unabhängig vom Android-Lebenszyklus sein.
Dringend empfohlen |
ViewModels sollte keinen Verweis auf einen Lebenszyklustyp enthalten. Übergeben Sie Activity, Fragment, Context oder Resources nicht als Abhängigkeit.
Wenn für etwas in ViewModel ein Context erforderlich ist, sollten Sie unbedingt prüfen, ob sich das in der richtigen Ebene befindet. |
Koroutinen und Abläufe verwenden.
Dringend empfohlen |
ViewModel interagiert mit den Daten- oder Domainebenen mithilfe von:
|
Verwenden Sie ViewModels auf Bildschirmebene.
Dringend empfohlen |
Verwenden Sie ViewModels nicht in wiederverwendbaren Elementen der Benutzeroberfläche. Sie sollten ViewModels in folgenden Ländern verwenden:
|
Verwenden Sie einfache State Holder-Klassen in wiederverwendbaren UI-Komponenten.
Dringend empfohlen |
Verwenden Sie einfache State Holder-Klassen, um Komplexität in wiederverwendbaren UI-Komponenten zu bewältigen. Auf diese Weise kann der Zustand extern hochgezogen und gesteuert werden. |
AndroidViewModel darf nicht verwendet werden.
Empfohlen |
Verwenden Sie die Klasse ViewModel , nicht AndroidViewModel . Die Klasse Application sollte nicht in ViewModel verwendet werden. Verschieben Sie die Abhängigkeit stattdessen in die Benutzeroberfläche oder die Datenschicht. |
Stellt einen UI-Status bereit.
Empfohlen |
ViewModels sollte Daten über eine einzige Property namens uiState für die Benutzeroberfläche bereitstellen. Wenn auf der Benutzeroberfläche mehrere, nicht zusammenhängende Daten angezeigt werden, kann die VM mehrere UI-Statusattribute verfügbar machen.
|
Das folgende Snippet veranschaulicht, wie der UI-Status aus einem ViewModel angezeigt wird:
@HiltViewModel
class BookmarksViewModel @Inject constructor(
newsRepository: NewsRepository
) : ViewModel() {
val feedState: StateFlow<NewsFeedUiState> =
newsRepository
.getNewsResourcesStream()
.mapToFeedState(savedNewsResourcesState)
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = NewsFeedUiState.Loading
)
// ...
}
Lebenszyklus
Im Folgenden finden Sie einige Best Practices für die Arbeit mit der Android-App Lebenszyklus:
Empfehlung | Beschreibung |
---|---|
Überschreiben Sie keine Lebenszyklusmethoden in Aktivitäten oder Fragmenten.
Dringend empfohlen |
Überschreiben Sie keine Lebenszyklusmethoden wie onResume in Aktivitäten oder Fragmenten. Verwenden Sie stattdessen LifecycleObserver . Wenn die App Arbeiten ausführen muss, wenn der Lebenszyklus einen bestimmten Lifecycle.State erreicht, verwenden Sie die repeatOnLifecycle API. |
Das folgende Snippet beschreibt, wie Vorgänge bei einer bestimmten Lebenszyklusstatus:
Aufrufe
class MyFragment: Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
// ...
}
override fun onPause(owner: LifecycleOwner) {
// ...
}
}
}
}
Schreiben
@Composable
fun MyApp() {
val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(lifecycleOwner, ...) {
val lifecycleObserver = object : DefaultLifecycleObserver {
override fun onStop(owner: LifecycleOwner) {
// ...
}
}
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
onDispose {
lifecycleOwner.lifecycle.removeObserver(lifecycleObserver)
}
}
}
Abhängigkeiten verarbeiten
Beim Verwalten von Abhängigkeiten sollten Sie mehrere Best Practices beachten. zwischen Komponenten:
Empfehlung | Beschreibung |
---|---|
Verwenden Sie eine Abhängigkeitsinjektion.
Dringend empfohlen |
Orientieren Sie sich an den Best Practices für Abhängigkeitseinschleusung, vor allem für die Konstruktor-Einschleusung, sofern möglich. |
Wechseln Sie bei Bedarf zu einer Komponente.
Dringend empfohlen |
Wechseln Sie zu einem Abhängigkeitscontainer, wenn der Typ änderbare Daten enthält, die freigegeben werden müssen, oder wenn die Initialisierung des Typs teuer ist und in der App häufig verwendet wird. |
Verwenden Sie Hilt.
Empfohlen |
Verwenden Sie Hilt oder manuelle Abhängigkeitsinjektion in einfachen Apps. Verwende Hilt, wenn dein Projekt komplex genug ist. Beispiele:
<ph type="x-smartling-placeholder">
|
Testen
Hier einige Best Practices für Tests:
Empfehlung | Beschreibung |
---|---|
Wissen, was Sie testen sollten
Dringend empfohlen |
Sofern das Projekt nicht so einfach ist wie eine Hello World-App, sollten Sie zumindest Folgendes testen:
|
Fälschungen sind lieber.
Dringend empfohlen |
Weitere Informationen finden Sie in der Dokumentation zur Verwendung von Test-Doubles in der Android-Dokumentation. |
Testen Sie StateFlows.
Dringend empfohlen |
Beim Testen von StateFlow :
<ph type="x-smartling-placeholder">
|
Weitere Informationen finden Sie im Leitfaden zu Tests in Android-DAC.
Modelle
Bei der Entwicklung von Modellen in Ihren Apps sollten Sie diese Best Practices beachten:
Empfehlung | Beschreibung |
---|---|
Ein Modell pro Ebene in komplexen Apps erstellen
Empfohlen |
In komplexen Apps können Sie neue Modelle in verschiedenen Ebenen oder Komponenten erstellen, wenn dies sinnvoll ist. Betrachten Sie die folgenden Beispiele:
|
Namenskonventionen
Beim Benennen Ihrer Codebasis sollten Sie die folgenden Best Practices beachten:
Empfehlung | Beschreibung |
---|---|
Benennungsmethoden
Optional |
Methoden sollten eine Verbformulierung sein. Beispiel: makePayment() . |
Benennungseigenschaften.
Optional |
Attribute sollten eine Nominalphrase sein. Beispiel: inProgressTopicSelection . |
Datenstreams benennen
Optional |
Wenn eine Klasse einen Flow-Stream, LiveData oder einen anderen Stream verfügbar macht, lautet die Namenskonvention get{model}Stream() . Beispiel: getAuthorStream(): Flow<Author>
Wenn die Funktion eine Liste von Modellen zurückgibt, sollte der Modellname im Plural sein: getAuthorsStream(): Flow<List<Author>> |
Implementierungen von Benennungsschnittstellen
Optional |
Die Namen für die Implementierungen von Schnittstellen sollten aussagekräftig sein. Verwenden Sie Default als Präfix, wenn kein besserer Name gefunden werden kann. Für eine NewsRepository -Schnittstelle könnten Sie beispielsweise OfflineFirstNewsRepository oder InMemoryNewsRepository verwenden. Wenn Sie keinen guten Namen finden, verwenden Sie DefaultNewsRepository .
Gefälschte Implementierungen sollten das Präfix Fake haben, wie in FakeAuthorsRepository . |