Auf dieser Seite werden mehrere Best Practices und Empfehlungen zur Architektur vorgestellt. Wenn Sie sie übernehmen, können Sie die Qualität, Robustheit und Skalierbarkeit Ihrer App verbessern. Außerdem erleichtern sie die Wartung und das Testen Ihrer App.
Die Best Practices unten sind nach Themen gruppiert. Jede hat eine Priorität, die angibt, wie stark die Empfehlung ist. Die Liste der Prioritäten sieht so aus:
- Dringend empfohlen:Implementieren Sie diese Best Practice, es sei denn, sie widerspricht Ihrem Ansatz grundlegend.
- Empfohlen:Diese Best Practice wird Ihre App wahrscheinlich verbessern.
- Optional:Diese Best Practice kann Ihre App unter bestimmten Umständen verbessern.
Mehrschichtige Architektur
Unsere empfohlene mehrschichtige Architektur bevorzugt die Trennung von Zuständigkeiten. Sie leitet die Benutzeroberfläche von Datenmodellen ab, entspricht dem Prinzip der Single Source of Truth, und folgt den Prinzipien des unidirektionalen Datenflusses. Hier sind einige Best Practices für die mehrschichtige Architektur:
| Empfehlung | Beschreibung |
|---|---|
| Verwenden Sie eine klar definierte Datenschicht.
Dringend empfohlen |
Die Datenschicht stellt Anwendungsdaten für den Rest der App bereit und enthält den Großteil der Geschäftslogik Ihrer App.
|
| Verwenden Sie eine klar definierte UI-Schicht.
Dringend empfohlen |
Die UI-Schicht zeigt die Anwendungsdaten auf dem Bildschirm an und dient als primärer Punkt der Nutzerinteraktion. Jetpack Compose ist das empfohlene moderne Toolkit für die Erstellung der Benutzeroberfläche Ihrer App.
|
| Stellen Sie Anwendungsdaten aus der Datenschicht über ein Repository bereit.
Dringend empfohlen |
Achten Sie darauf, dass Komponenten in der UI-Schicht wie zusammensetzbare Funktionen oder ViewModels nicht direkt mit einer Datenquelle interagieren. Beispiele für Datenquellen:
|
| Verwenden Sie Coroutinen und Flows.
Dringend empfohlen |
Verwenden Sie Coroutinen und Flows, um zwischen Schichten zu kommunizieren.
Weitere Informationen zu Best Practices für Coroutinen finden Sie unter Best Practices für Coroutinen in Android. |
| Verwenden Sie eine Domain-Schicht.
Empfohlen für große Apps |
Verwenden Sie eine Domain-Schicht mit Anwendungsfällen, wenn Sie Geschäftslogik wiederverwenden müssen, die mit der Datenschicht über mehrere ViewModels interagiert, oder wenn Sie die Komplexität der Geschäftslogik eines bestimmten ViewModels vereinfachen möchten. |
UI-Layer
Die Rolle der UI-Schicht ist es, die Anwendungsdaten auf dem Bildschirm anzuzeigen und als primärer Punkt der Nutzerinteraktion zu dienen. Hier sind einige Best Practices für die UI-Schicht:
| Empfehlung | Beschreibung |
|---|---|
| Folgen Sie dem unidirektionalen Datenfluss (Unidirectional Data Flow, UDF).
Dringend empfohlen |
Folgen Sie den Prinzipien des unidirektionalen Datenflusses (Unidirectional Data Flow, UDF). Dabei stellen ViewModels den UI-Status mithilfe des Beobachtermusters bereit und empfangen Aktionen von der Benutzeroberfläche über Methodenaufrufe. |
| Verwenden Sie AAC-ViewModels, wenn ihre Vorteile für Ihre App gelten.
Dringend empfohlen |
Verwenden Sie AAC-ViewModels, um Geschäftslogik zu verarbeiten und Anwendungsdaten abzurufen, um den UI-Status für die Benutzeroberfläche bereitzustellen.
Weitere Informationen zu Best Practices für ViewModels finden Sie unter Architektur-Empfehlungen. Weitere Informationen zu den Vorteilen von ViewModels finden Sie unter Das ViewModel als Status-Holder für die Geschäftslogik. |
| Verwenden Sie die lebenszyklusbezogene Erfassung des UI-Status.
Dringend empfohlen |
Erfassen Sie den UI-Status über die Benutzeroberfläche mit dem entsprechenden lebenszyklusbezogenen Coroutinen-Builder, collectAsStateWithLifecycle.
Weitere Informationen zu |
| Senden Sie keine Ereignisse vom ViewModel an die Benutzeroberfläche.
Dringend empfohlen |
Verarbeiten Sie das Ereignis sofort im ViewModel und veranlassen Sie eine Statusaktualisierung mit dem Ergebnis der Ereignisverarbeitung. Weitere Informationen zu UI-Ereignissen finden Sie unter ViewModel-Ereignisse verarbeiten. |
| Verwenden Sie eine Single-Activity-Anwendung.
Dringend empfohlen |
Verwenden Sie Navigation 3, um zwischen Bildschirmen zu wechseln und Deep-Links zu Ihrer App zu erstellen, wenn Ihre App mehr als einen Bildschirm hat. |
| Verwenden Sie Jetpack Compose.
Dringend empfohlen |
Verwenden Sie Jetpack Compose, um neue Apps für Smartphones, Tablets, faltbare Geräte und Wear OS zu erstellen. |
Das folgende Snippet zeigt, wie Sie den UI-Status lebenszyklusbezogen erfassen:
@Composable
fun MyScreen(
viewModel: MyViewModel = viewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}
ViewModel
ViewModels sind für die Bereitstellung des UI-Status und den Zugriff auf die Datenschicht zuständig. Hier sind einige Best Practices für ViewModels:
| Empfehlung | Beschreibung |
|---|---|
| Halten Sie ViewModels unabhängig vom Android-Lebenszyklus.
Dringend empfohlen |
Halten Sie in ViewModels keine Referenz auf einen lebenszyklusbezogenen Typ. Übergeben Sie Activity, Context oder Resources nicht als Abhängigkeit.
Wenn etwas im ViewModel einen Context benötigt, prüfen Sie sorgfältig, ob es sich in der richtigen Schicht befindet. |
| Verwenden Sie Coroutinen und Flows.
Dringend empfohlen |
Das ViewModel interagiert mit der Daten- oder Domain-Schicht mit Folgendem:
|
| Verwenden Sie ViewModels auf Bildschirmebene.
Dringend empfohlen |
Verwenden Sie keine ViewModels in wiederverwendbaren UI-Elementen. Sie sollten ViewModels in folgenden Fällen verwenden:
Verwenden Sie für komplexere zusammensetzbare Funktionen oder solche mit dynamischem Verhalten basierend auf dem Status |
| Verwenden Sie einfache Status-Holder-Klassen in wiederverwendbaren UI-Komponenten.
Dringend empfohlen |
Verwenden Sie einfache Status-Holder-Klassen, um die Komplexität in wiederverwendbaren UI-Komponenten zu verarbeiten. Dadurch kann der Status ausgelagert und extern gesteuert werden. |
Verwenden Sie nicht AndroidViewModel.
Empfohlen |
Verwenden Sie die ViewModel Klasse und nicht AndroidViewModel. Verwenden Sie die Klasse Application nicht im ViewModel. Verschieben Sie die Abhängigkeit stattdessen in die UI- oder Datenschicht. |
| Stellen Sie einen UI-Status bereit.
Empfohlen |
Sorgen Sie dafür, dass Ihre ViewModels Daten über eine einzelne Property namens uiState für die Benutzeroberfläche bereitstellen. Wenn die Benutzeroberfläche mehrere unabhängige Daten enthält, kann das ViewModel mehrere UI-Status-Properties bereitstellen.
|
Das folgende Snippet zeigt, wie Sie den UI-Status aus einem ViewModel bereitstellen:
@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
Beachten Sie die Best Practices für die Arbeit mit dem Lebenszyklus von Aktivitäten :
| Empfehlung | Beschreibung |
|---|---|
Verwenden Sie lebenszyklusbezogene Effekte in zusammensetzbaren Funktionen, anstatt die Lebenszyklus-Callbacks von Activity zu überschreiben.
Dringend empfohlen |
Überschreiben Sie keine Lebenszyklusmethoden von
|
Das folgende Snippet zeigt, wie Sie Vorgänge in einem bestimmten Lebenszyklusstatus ausführen:
@Composable
fun LocationChangedEffect(
locationManager: LocationManager,
onLocationChanged: (Location) -> Unit
) {
val currentOnLocationChanged by rememberUpdatedState(onLocationChanged)
LifecycleStartEffect(locationManager) {
val listener = LocationListener { newLocation ->
currentOnLocationChanged(newLocation)
}
try {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
1000L,
1f,
listener,
)
} catch (e: SecurityException) {
// TODO: Handle missing permissions
}
onStopOrDispose {
locationManager.removeUpdates(listener)
}
}
}
Abhängigkeiten verarbeiten
Beachten Sie die Best Practices beim Verwalten von Abhängigkeiten zwischen Komponenten:
| Empfehlung | Beschreibung |
|---|---|
| Verwenden Sie die Abhängigkeitsinjektion.
Dringend empfohlen |
Beachten Sie die Best Practices für die Abhängigkeitsinjektion, vor allem die Konstruktorinjektion, wenn möglich. |
| Beschränken Sie den Bereich bei Bedarf auf eine Komponente.
Dringend empfohlen |
Beschränken Sie den Bereich auf einen Abhängigkeitscontainer, wenn der Typ veränderliche Daten enthält, die freigegeben werden müssen, oder wenn der Typ teuer zu initialisieren ist und häufig in der App verwendet wird. |
| Verwenden Sie Hilt.
Empfohlen |
Verwenden Sie Hilt oder die manuelle Abhängigkeitsinjektion in einfachen Apps. Verwenden Sie Hilt, wenn Ihr Projekt komplex genug ist, z. B. wenn es Folgendes enthält:
|
Test
Hier sind einige Best Practices für Tests:
| Empfehlung | Beschreibung |
|---|---|
| Wissen, was getestet werden muss.
Dringend empfohlen |
Sofern das Projekt nicht so einfach wie eine „Hello World“-App ist, testen Sie es. Es sollte mindestens Folgendes enthalten:
|
| Bevorzugen Sie Fakes gegenüber Mocks.
Dringend empfohlen |
Weitere Informationen zur Verwendung von Fakes finden Sie unter Test Doubles in Android verwenden. |
| Testen Sie StateFlows.
Dringend empfohlen |
Gehen Sie beim Testen von StateFlow so vor:
|
Weitere Informationen finden Sie unter Was sollte in Android getestet werden? und Compose-Layout testen.
Modelle
Beachten Sie diese Best Practices, wenn Sie Modelle in Ihren Apps entwickeln:
| Empfehlung | Beschreibung |
|---|---|
| Erstellen Sie in komplexen Apps ein Modell pro Schicht.
Empfohlen |
Erstellen Sie in komplexen Apps neue Modelle in verschiedenen Schichten oder Komponenten, wenn es sinnvoll ist. Betrachten Sie hierzu folgende Beispiele:
|
Namenskonventionen
Beachten Sie beim Benennen Ihrer Codebasis die folgenden Best Practices:
| Empfehlung | Beschreibung |
|---|---|
| Methoden benennen.
Optional |
Verwenden Sie Verbgruppen, um Methoden zu benennen, z. B. makePayment(). |
| Properties benennen.
Optional |
Verwenden Sie Nomengruppen, um Properties zu benennen, z. B. inProgressTopicSelection. |
| Datenstreams benennen.
Optional |
Wenn eine Klasse einen Flow-Stream oder einen anderen Stream bereitstellt, lautet die Namenskonvention get{model}Stream, z. B. getAuthorStream(): Flow<Author>.
Wenn die Funktion eine Liste von Modellen zurückgibt, verwenden Sie den Plural des Modellnamens: getAuthorsStream(): Flow<List<Author>>. |
| Implementierungen von Schnittstellen benennen.
Optional |
Verwenden Sie aussagekräftige Namen für die Implementierungen von Schnittstellen. Verwenden Sie Default als Präfix, wenn kein besserer Name gefunden werden kann. Für eine NewsRepository-Schnittstelle können Sie beispielsweise OfflineFirstNewsRepository oder InMemoryNewsRepository verwenden. Wenn Sie keinen guten Namen finden, verwenden Sie DefaultNewsRepository.
Stellen Sie dem Namen von Fake-Implementierungen das Präfix Fake voran, z. B. FakeAuthorsRepository. |
Zusätzliche Ressourcen
Weitere Informationen zur Android-Architektur finden Sie in den folgenden zusätzlichen Ressourcen: