Na tej stronie znajdziesz kilka sprawdzonych metod i zaleceń dotyczących architektury. Zastosuj je, aby poprawić jakość, niezawodność i skalowalność swojej aplikacji. Poza tym ułatwiają obsługę i testowanie aplikacji.
Sprawdzone metody wymienione poniżej są pogrupowane według tematów. Każdy z nich ma priorytet, który odzwierciedla jak zdecydowanie jest to zalecane przez zespół. Oto lista priorytetów:
- Zdecydowanie zalecane: zalecamy wdrożenie tej metody, chyba że sprzeczne ze sobą co jest zgodne z Pana/Pani firmą.
- Zalecane: ta metoda prawdopodobnie poprawi Twoją aplikację.
- Opcjonalnie: w pewnych okolicznościach ta praktyka może poprawić działanie aplikacji.
Warstwowa architektura
Nasza zalecana architektura warstwowa preferuje dzielenie potencjalnych problemów. it Napędza UI z modeli danych, jest zgodny z zasadą jednego źródła danych, i jest zgodny z zasadami jednokierunkowego przepływu danych. Oto kilka najlepszych w przypadku architektury warstwowej:
Rekomendacja | Opis |
---|---|
Użyj jasno określonej warstwy danych.
Zdecydowanie zalecane |
Warstwa danych ujawnia dane aplikacji reszty aplikacji i zawiera zdecydowaną większość logiki biznesowej aplikacji.
|
Użyj jasno określonej warstwy interfejsu.
Zdecydowanie zalecane |
Warstwa interfejsu wyświetla na ekranie dane aplikacji i stanowi główny punkt interakcji użytkownika.
|
Warstwa danych powinna udostępniać dane aplikacji za pomocą repozytorium.
Zdecydowanie zalecane |
Komponenty w warstwie interfejsu, takie jak obiekty kompozycyjne, aktywności czy ViewModels, nie powinny wchodzić w bezpośrednią interakcję ze źródłem danych. Przykłady źródeł danych:
|
Używaj współrzędnych i przepływów.
Zdecydowanie zalecane |
Do komunikacji między warstwami używaj współrzędnych i przepływów.
Więcej sprawdzonych metod dotyczących współprac znajdziesz tutaj |
Użyj warstwy domeny.
Polecane w dużych aplikacjach |
Użyj warstwy domeny, jeśli chcesz ponownie wykorzystać logikę biznesową, która współdziała z warstwą danych w wielu modelach ViewModel, lub jeśli chcesz uprościć logikę biznesową danego modelu widoku. |
warstwa interfejsu
Rola warstwy interfejsu polega na wyświetlaniu danych aplikacji na ekranie. i służą za główny punkt interakcji użytkownika. Oto kilka sprawdzonych metod dla warstwy interfejsu użytkownika:
Rekomendacja | Opis |
---|---|
Wykonaj czynności opisane w artykule Niekierunkowy przepływ danych (UDF).
Zdecydowanie zalecane |
Przestrzegaj zasad jednokierunkowego przepływu danych (UDF), w którym modele ViewModels ujawniają stan interfejsu użytkownika za pomocą wzorca obserwatora i odbierają działania z interfejsu za pomocą wywołań metod. |
Używaj modelu AAC ViewModels, jeśli jego zalety mają zastosowanie do Twojej aplikacji.
Zdecydowanie zalecane |
Modele widoków AAC służą do obsługi logiki biznesowej i do pobierania danych aplikacji w celu ujawnienia stanu interfejsu użytkownika (komunikacji lub widoków Androida).
Zobacz więcej sprawdzonych metod ViewModel. Poznaj zalety modeli widoków. |
Używaj kolekcji stanów interfejsu uwzględniającego cykl życia.
Zdecydowanie zalecane |
Zbieraj informacje o stanie interfejsu z UI za pomocą odpowiedniego kreatora współpracowania dostosowanego do cyklu życia: repeatOnLifecycle w systemie wyświetlania i collectAsStateWithLifecycle w Jetpack Compose.
Dowiedz się więcej o Dowiedz się więcej na ten temat: |
Nie wysyłaj zdarzeń z modelu ViewModel do interfejsu użytkownika.
Zdecydowanie zalecane |
Przetwórz zdarzenie natychmiast w modelu ViewModel i wywołaj aktualizację stanu w wyniku obsługi zdarzenia. Więcej informacji o zdarzeniach w interfejsie znajdziesz tutaj. |
Użyj aplikacji składającej się z pojedynczej czynności.
Zalecane |
Jeśli Twoja aplikacja ma więcej niż 1 ekran, do przechodzenia między ekranami i precyzyjnych linków do aplikacji używaj fragmentów nawigacji lub kompozycji nawigacyjnych. |
korzystać z Jetpack Compose;
Zalecane |
Za pomocą Jetpack Compose możesz tworzyć nowe aplikacje na telefony, tablety, urządzenia składane i Wear OS. |
Poniższy fragment kodu opisuje, jak rejestrować stan UI w kontekście cyklu życia w sposób:
Wyświetlenia
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
}
}
}
}
}
Compose
@Composable
fun MyScreen(
viewModel: MyViewModel = viewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}
Wyświetl model
Modele ViewModels odpowiadają za udostępnianie stanu interfejsu użytkownika i dostępu do funkcji warstwy danych. Oto kilka sprawdzonych metod dotyczących modeli widoków:
Rekomendacja | Opis |
---|---|
Modele widoku danych powinny być niezależne od cyklu życia Androida.
Zdecydowanie zalecane |
Obiekty ViewModels nie powinny zawierać odwołania do żadnego typu powiązanego z cyklem życia. Nie przekazuj zasady Activity, Fragment, Context ani Resources jako zależności.
Jeśli coś wymaga Context w modelu widoku, musisz zdecydowanie sprawdzić, czy znajduje się on we właściwej warstwie. |
Używaj współrzędnych i przepływów.
Zdecydowanie zalecane |
Model widoku danych współdziała z warstwami danych lub domeny za pomocą:
|
Używaj modeli widoków na poziomie ekranu.
Zdecydowanie zalecane |
Nie używaj modeli ViewModels w elementach interfejsu wielokrotnego użytku. Modeli ViewModel należy używać w tych obszarach:
|
Używaj zwykłych klas obiektów stanowych w komponentach interfejsu wielokrotnego użytku.
Zdecydowanie zalecane |
Używaj zwykłych klas obiektów stanu do obsługi złożoności komponentów interfejsu wielokrotnego użytku. Dzięki temu stan można podnosić i kontrolować z zewnątrz. |
Nie używaj AndroidViewModel .
Zalecane |
Używaj zajęć ViewModel , a nie AndroidViewModel . W modelu ViewModel nie należy używać klasy Application . Zamiast tego przenieś zależność do interfejsu użytkownika lub warstwy danych. |
udostępniać stan interfejsu,
Zalecane |
Modele widoków danych powinny udostępniać dane w interfejsie za pomocą jednej usługi o nazwie uiState . Jeśli interfejs użytkownika wyświetla wiele niepowiązanych ze sobą elementów danych, maszyna wirtualna może udostępniać wiele właściwości stanu interfejsu.
|
Ten fragment kodu opisuje, jak udostępnić stan interfejsu za pomocą modelu 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
Oto kilka sprawdzonych metod pracy z Androidem cykl życia:
Rekomendacja | Opis |
---|---|
Nie zastępuj metod cyklu życia w aktywnościach ani fragmentach.
Zdecydowanie zalecane |
Nie zastępuj metod cyklu życia, takich jak onResume , w działaniach lub fragmentach. Zamiast niego użyj LifecycleObserver . Jeśli aplikacja musi działać, gdy cykl życia osiągnie określoną wartość Lifecycle.State , użyj interfejsu API repeatOnLifecycle . |
Fragment kodu poniżej pokazuje, jak wykonywać operacje na określonych danych Stan cyklu życia:
Wyświetlenia
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) {
// ...
}
}
}
}
Compose
@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)
}
}
}
Obsługa zależności
Jest kilka sprawdzonych metod, o których warto pamiętać, zarządzając zależnościami. między komponentami:
Rekomendacja | Opis |
---|---|
Użyj wstrzykiwania zależności.
Zdecydowanie zalecane |
Stosuj sprawdzone metody dotyczące wstrzykiwania zależności, głównie wstrzykiwania przez konstruktor, gdy to możliwe. |
W razie potrzeby ustaw zakres na komponent.
Zdecydowanie zalecane |
Ustaw zakres na kontener zależności, gdy typ zawiera zmienne dane, które należy udostępnić, lub gdy typ jest kosztowny w celu zainicjowania i jest powszechnie używany w aplikacji. |
Użyj Hilt.
Zalecane |
W prostych aplikacjach używaj Hilt lub ręcznego wstrzykiwania zależności. Jeśli Twój projekt jest wystarczająco złożony, użyj narzędzia Hilt. Jeśli na przykład masz:
|
Testowanie
Poniżej znajdziesz sprawdzone metody testowania:
Rekomendacja | Opis |
---|---|
Co warto przetestować.
Zdecydowanie zalecane |
Jeśli projekt nie jest tak prosty jak aplikacja Hello World, warto ją przetestować. W tym celu:
|
Wolę fałszerstwo niż psikusy.
Zdecydowanie zalecane |
Więcej informacji znajdziesz w artykule o używaniu wartości deweloperskich w wersji testowej w dokumentacji Androida. |
Przetestuj przepływy StateFlows.
Zdecydowanie zalecane |
Podczas testowania aplikacji StateFlow :
|
Więcej informacji znajdziesz w przewodniku po funkcjach DAC na Androida.
Modele
Podczas tworzenia modeli w aplikacjach przestrzegaj tych sprawdzonych metod:
Rekomendacja | Opis |
---|---|
Tworzenie modelu na warstwę w złożonych aplikacjach.
Zalecane |
W złożonych aplikacjach w razie potrzeby twórz nowe modele w różnych warstwach lub komponentach. Zobacz te przykłady:
|
Konwencje nazewnictwa
Nazywając bazę kodu, pamiętaj o tych sprawdzonych metodach:
Rekomendacja | Opis |
---|---|
Metody nazewnictwa.
Opcjonalny |
Metody powinny być wyrażeniami czasownikowymi. Na przykład: makePayment() . |
Właściwości nazewnictwa.
Opcjonalny |
Właściwości powinny być powiązane z funkcją rzeczownikową. Na przykład: inProgressTopicSelection . |
Nazewnictwo strumieni danych.
Opcjonalny |
Gdy klasa udostępnia strumień Flow, LiveData lub dowolny inny strumień, konwencja nazewnictwa jest zgodna z konwencją get{model}Stream() . Na przykład: getAuthorStream(): Flow<Author>
Jeśli funkcja zwraca listę modeli, nazwa modelu musi być w liczbie mnogiej: getAuthorsStream(): Flow<List<Author>> |
Implementacje interfejsów nazewnictwa.
Opcjonalny |
Nazwy implementacji interfejsów powinny być zrozumiałe. Jeśli nie można znaleźć lepszej nazwy, ustaw prefiks Default . W przypadku interfejsu NewsRepository można na przykład mieć wartość OfflineFirstNewsRepository lub InMemoryNewsRepository . Jeśli nie możesz znaleźć dobrego imienia, użyj DefaultNewsRepository .
Fałszywe implementacje powinny być poprzedzone ciągiem Fake , np. FakeAuthorsRepository . |