Na tej stronie znajdziesz kilka sprawdzonych metod i zaleceń dotyczących architektury. Wprowadź je, aby poprawić jakość, niezawodność i skalowalność aplikacji. Ułatwiają też utrzymywanie i testowanie aplikacji.
Sprawdzone metody poniżej są pogrupowane według tematu. Każda z nich ma priorytet, który odzwierciedla siłę rekomendacji. Lista priorytetów jest następująca:
- Zdecydowanie zalecane: wdróż tę praktykę, chyba że jest ona sprzeczna z Twoim podejściem.
- Zalecane: ta sprawdzona metoda prawdopodobnie poprawi jakość Twojej aplikacji.
- Opcjonalnie: w określonych okolicznościach może to poprawić jakość aplikacji.
Architektura warstwowa
Zalecana przez nas architektura warstwowa sprzyja rozdzieleniu zadań. Wyświetla interfejs na podstawie modeli danych, jest zgodny z zasadą jednego źródła danych i przestrzega zasad jednokierunkowego przepływu danych. Oto kilka sprawdzonych metod dotyczących architektury warstwowej:
| Rekomendacja | Opis |
|---|---|
| Używaj jasno określonej warstwy danych.
Zdecydowanie zalecane |
Warstwa danych udostępnia dane aplikacji pozostałym jej częściom i zawiera większość logiki biznesowej aplikacji.
|
| Używaj wyraźnie zdefiniowanej warstwy interfejsu.
Zdecydowanie zalecane |
Warstwa interfejsu wyświetla dane aplikacji na ekranie i służy jako główny punkt interakcji użytkownika. Jetpack Compose to zalecany nowoczesny zestaw narzędzi do tworzenia interfejsu aplikacji.
|
| Udostępnij dane aplikacji z warstwy danych za pomocą repozytorium.
Zdecydowanie zalecane |
Upewnij się, że komponenty w warstwie interfejsu, takie jak funkcje kompozycyjne czy modele ViewModel, nie wchodzą w bezpośrednią interakcję ze źródłem danych. Przykłady źródeł danych:
|
| Używaj współprogramów i przepływów.
Zdecydowanie zalecane |
Do komunikacji między warstwami używaj korutyn i przepływów.
Więcej informacji o sprawdzonych metodach dotyczących współprogramów znajdziesz w artykule Sprawdzone metody dotyczące współprogramów na Androidzie. |
| Użyj warstwy domeny.
Zalecane w przypadku dużych aplikacji |
Używaj warstwy domeny z przypadkami użycia, jeśli chcesz ponownie wykorzystać logikę biznesową, która wchodzi w interakcję z warstwą danych w wielu modelach ViewModel, lub uprościć złożoność logiki biznesowej konkretnego modelu ViewModel. |
Warstwa interfejsu
Warstwa interfejsu służy do wyświetlania danych aplikacji na ekranie i jest głównym punktem interakcji użytkownika. Oto kilka sprawdzonych metod dotyczących warstwy interfejsu:
| Rekomendacja | Opis |
|---|---|
| Postępuj zgodnie z zasadami jednokierunkowego przepływu danych (UDF).
Zdecydowanie zalecane |
Postępuj zgodnie z zasadami jednokierunkowego przepływu danych (UDF), w których klasy ViewModel udostępniają stan interfejsu za pomocą wzorca obserwatora i otrzymują działania z interfejsu za pomocą wywołań metod. |
| Używaj AAC ViewModels, jeśli ich zalety mają zastosowanie w Twojej aplikacji.
Zdecydowanie zalecane |
Używaj AAC ViewModels do obsługi logiki biznesowej i pobierania danych aplikacji, aby udostępniać interfejsowi stan interfejsu.
Więcej informacji o sprawdzonych metodach dotyczących ViewModel znajdziesz w artykule Zalecenia dotyczące architektury. Więcej informacji o korzyściach klasy ViewModel znajdziesz w artykule ViewModel jako zmienna stanu logiki biznesowej. |
| Korzystaj ze zbierania stanu interfejsu, które uwzględnia cykl życia.
Zdecydowanie zalecane |
Zbierz stan interfejsu z interfejsu za pomocą odpowiedniego konstruktora współprogramu uwzględniającego cykl życia, collectAsStateWithLifecycle.
Więcej informacji o |
| Nie wysyłaj zdarzeń z ViewModel do interfejsu.
Zdecydowanie zalecane |
Natychmiast przetwórz zdarzenie w obiekcie ViewModel i wywołaj aktualizację stanu z wynikiem obsługi zdarzenia. Więcej informacji o zdarzeniach interfejsu znajdziesz w artykule Obsługa zdarzeń ViewModel. |
| Używaj aplikacji z jedną aktywnością.
Zdecydowanie zalecane |
Użyj Navigation 3, aby poruszać się między ekranami i precyzyjnie linkować do aplikacji, jeśli ma ona więcej niż 1 ekran. |
| Używaj Jetpack Compose.
Zdecydowanie zalecane |
Używaj Jetpack Compose do tworzenia nowych aplikacji na telefony, tablety, urządzenia składane i zegarki z Wear OS. |
Poniższy fragment kodu pokazuje, jak zbierać stan interfejsu w sposób uwzględniający cykl życia:
@Composable
fun MyScreen(
viewModel: MyViewModel = viewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}
ViewModel
ViewModele odpowiadają za udostępnianie stanu interfejsu i dostęp do warstwy danych. Oto kilka sprawdzonych metod dotyczących klasy ViewModel:
| Rekomendacja | Opis |
|---|---|
| Zachowaj niezależność obiektów ViewModel od cyklu życia Androida.
Zdecydowanie zalecane |
W klasach ViewModel nie przechowuj odwołań do żadnych typów związanych z cyklem życia. Nie przekazuj jako zależności wartości Activity, Context ani Resources.
Jeśli coś wymaga Context w ViewModelu, dokładnie sprawdź, czy jest to odpowiednia warstwa. |
| Używaj współprogramów i przepływów.
Zdecydowanie zalecane |
ViewModel wchodzi w interakcję z warstwami danych lub domeny za pomocą tych elementów:
|
| Używaj obiektów ViewModel na poziomie ekranu.
Zdecydowanie zalecane |
Nie używaj klas ViewModel w elementach interfejsu, które można ponownie wykorzystać. Modelu widoku należy używać w tych przypadkach:
|
| Używaj zwykłych klas przechowujących stan w komponentach interfejsu wielokrotnego użytku.
Zdecydowanie zalecane |
Używaj zwykłych klas przechowujących stan do obsługi złożoności w komponentach interfejsu wielokrotnego użytku. W takim przypadku stan może być przeniesiony i sterowany zewnętrznie. |
Nie używaj AndroidViewModel.
Zalecane |
Użyj klasy ViewModel, a nie AndroidViewModel. Nie używaj klasy Application w obiekcie ViewModel. Zamiast tego przenieś zależność do interfejsu lub warstwy danych. |
| Udostępnij stan interfejsu.
Zalecane |
Spraw, aby obiekty ViewModel udostępniały dane interfejsowi za pomocą jednej właściwości o nazwie uiState. Jeśli interfejs wyświetla wiele niepowiązanych ze sobą danych, maszyna wirtualna może udostępniać wiele właściwości stanu interfejsu.
|
Poniższy fragment kodu pokazuje, jak udostępnić stan interfejsu z klasy ViewModel:
@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
)
// ...
}
Cykl życia
Postępuj zgodnie ze sprawdzonymi metodami dotyczącymi cyklu życia aktywności:
| Rekomendacja | Opis |
|---|---|
Używaj w kompozycjach efektów uwzględniających cykl życia zamiast zastępować wywołania zwrotne cyklu życia Activity.
Zdecydowanie zalecane |
Nie zastępuj
|
Poniższy fragment kodu pokazuje, jak wykonywać operacje w określonym stanie cyklu życia:
@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)
}
}
}
Obsługa zależności
Podczas zarządzania zależnościami między komponentami postępuj zgodnie ze sprawdzonymi metodami:
| Rekomendacja | Opis |
|---|---|
| Używaj wstrzykiwania zależności.
Zdecydowanie zalecane |
Stosuj sprawdzone metody wstrzykiwania zależności, a w miarę możliwości korzystaj głównie z wstrzykiwania przez konstruktor. |
| W razie potrzeby ogranicz zakres do komponentu.
Zdecydowanie zalecane |
Ogranicz zakres do kontenera zależności, gdy typ zawiera modyfikowalne dane, które muszą być udostępniane, lub gdy typ jest kosztowny w inicjowaniu i jest szeroko stosowany w aplikacji. |
| Użyj Hilt.
Zalecane |
W prostych aplikacjach używaj Hilta lub ręcznego wstrzykiwania zależności. Używaj Hilta, jeśli Twój projekt jest wystarczająco złożony, np. zawiera któryś z tych elementów:
|
Testowanie
Oto kilka sprawdzonych metod testowania:
| Rekomendacja | Opis |
|---|---|
| Wiedzieć, co testować
Zdecydowanie zalecane |
Jeśli projekt nie jest tak prosty jak aplikacja „hello world”, przetestuj go. Powinny one zawierać co najmniej te informacje:
|
| Preferuj obiekty zastępcze zamiast atrap.
Zdecydowanie zalecane |
Więcej informacji o używaniu obiektów zastępczych znajdziesz w artykule Używanie obiektów zastępczych w Androidzie. |
| Testowanie StateFlows.
Zdecydowanie zalecane |
Podczas testowania StateFlow wykonaj te czynności:
|
Więcej informacji znajdziesz w artykułach Co testować na Androidzie i Testowanie układu Compose.
Modele
Podczas tworzenia modeli w aplikacjach stosuj te sprawdzone metody:
| Rekomendacja | Opis |
|---|---|
| W przypadku złożonych aplikacji utwórz model dla każdej warstwy.
Zalecane |
W przypadku złożonych aplikacji twórz nowe modele w różnych warstwach lub komponentach, gdy ma to sens. Oto przykłady:
|
Konwencje nazewnictwa
Podczas nazywania bazy kodu warto pamiętać o tych sprawdzonych metodach:
| Rekomendacja | Opis |
|---|---|
| Metody nazywania.
Opcjonalny |
Do nazywania metod używaj wyrażeń czasownikowych, np. makePayment(). |
| Nazewnictwo właściwości.
Opcjonalny |
Do nazywania właściwości używaj wyrażeń rzeczownikowych, np. inProgressTopicSelection. |
| Nazewnictwo strumieni danych.
Opcjonalny |
Gdy klasa udostępnia strumień Flow lub inny strumień, obowiązuje konwencja nazewnictwa get{model}Stream. Na przykład: getAuthorStream(): Flow<Author>.
Jeśli funkcja zwraca listę modeli, użyj nazwy modelu w liczbie mnogiej: getAuthorsStream(): Flow<List<Author>>. |
| Nazewnictwo implementacji interfejsów.
Opcjonalny |
Nadawaj implementacjom interfejsów rozpoznawalne nazwy. Jeśli nie można znaleźć lepszej nazwy, użyj prefiksu Default. Na przykład w przypadku interfejsu NewsRepository możesz mieć OfflineFirstNewsRepository lub InMemoryNewsRepository. Jeśli nie możesz znaleźć odpowiedniej nazwy, użyj DefaultNewsRepository.
Prefiksuj fałszywe implementacje symbolem Fake, np. FakeAuthorsRepository. |
Dodatkowe materiały
Więcej informacji o architekturze Androida znajdziesz w tych materiałach: