Omówienie LiveData Część pakietu Android Jetpack.
LiveData
to możliwy do obserwacji klasa posiadacza danych. W przeciwieństwie do zwykłych obserwowalnych danych LiveData uwzględnia cykl życia, co oznacza, że respektuje cykl życia innych komponentów aplikacji, takich jak działania, fragmenty czy usługi. Dzięki temu LiveData aktualizuje tylko obserwatorów komponentów aplikacji, którzy są w aktywnym cyklu życia.
LiveData uważa obserwatora reprezentowanego przez klasę Observer
za aktywny, jeśli jego cykl życia ma stan STARTED
lub RESUMED
. LiveData powiadamia o aktualizacjach tylko aktywnych obserwatorów. Nieaktywne obserwatorzy zarejestrowane, aby obserwować obiekty LiveData
, nie otrzymują powiadomień o zmianach.
Możesz zarejestrować obserwatora sparowanego z obiektem, który implementuje interfejs LifecycleOwner
. Ta relacja umożliwia usunięcie obserwatora, gdy stan odpowiedniego obiektu Lifecycle
zmieni się na DESTROYED
.
Jest to szczególnie przydatne w przypadku działań i fragmentów, ponieważ mogą one bezpiecznie obserwować obiekty LiveData
i nie martwić się wyciekami – aktywności i fragmenty są natychmiast anulowane po zniszczeniu ich cyklu życia.
Więcej informacji o korzystaniu z LiveData znajdziesz w artykule Praca z obiektami LiveData.
Zalety korzystania z LiveData
Korzystanie z LiveData przynosi następujące korzyści:
- Dopasowanie interfejsu użytkownika do stanu danych
- LiveData podąża za wzorcem obserwatora. LiveData powiadamia o zmianach danych źródłowych w obiektach
Observer
. Możesz skonsolidować kod, aby zaktualizować interfejs użytkownika w tych obiektachObserver
. Dzięki temu nie będzie trzeba aktualizować interfejsu przy każdej zmianie danych aplikacji, ponieważ obserwator robi to za Ciebie. - Brak wycieków pamięci
- Obserwatorzy są przypisani do obiektów
Lifecycle
i czyszczą się po nich po zniszczeniu powiązanego z nimi cyklu życia. - Brak awarii z powodu zatrzymanych działań
- Jeśli cykl życia obserwatora jest nieaktywny, na przykład w przypadku aktywności w stosie wstecznym, obserwator nie otrzyma żadnych zdarzeń LiveData.
- Koniec z ręczną obsługą cyklu życia produktu
- Komponenty interfejsu analizują tylko istotne dane i nie zatrzymują ani nie wznawiają obserwacji. LiveData automatycznie zarządza tym wszystkim, ponieważ podczas obserwacji wie o odpowiednich zmianach stanu cyklu życia.
- Zawsze aktualne dane
- Jeśli cykl życia stanie się nieaktywny, po ponownym aktywowaniu otrzyma najnowsze dane. Na przykład działanie działające w tle otrzymuje najnowsze dane zaraz po powrocie na pierwszy plan.
- Prawidłowe zmiany w konfiguracji
- Jeśli aktywność lub fragment zostaną odtworzone w wyniku zmiany konfiguracji, np. rotacji urządzenia, natychmiast otrzyma najnowsze dostępne dane.
- Udostępnianie materiałów
- Możesz rozszerzyć obiekt
LiveData
za pomocą wzorca singleton, aby opakować usługi systemowe tak, aby można je było udostępnić w aplikacji. ObiektLiveData
łączy się z usługą systemową raz, a każdy obserwator, który potrzebuje zasobu, może po prostu obejrzeć obiektLiveData
. Więcej informacji znajdziesz w sekcji Extend LiveData.
Praca z obiektami LiveData
Aby pracować z obiektami LiveData
, wykonaj te czynności:
- Utwórz instancję
LiveData
, aby przechowywać dane określonego typu. Zwykle odbywa się to w klasieViewModel
. - Utwórz obiekt
Observer
definiujący metodęonChanged()
, która kontroluje to, co się dzieje, gdy zmieniają się dane przechowywane w obiekcieLiveData
. Zwykle w kontrolerze interfejsu tworzysz obiektObserver
, np. aktywność lub fragment. Dołącz obiekt
Observer
do obiektuLiveData
metodąobserve()
. Metodaobserve()
pobiera obiektLifecycleOwner
. Spowoduje to subskrypcję obiektuObserver
w obiekcieLiveData
, dzięki czemu będzie on powiadamiany o zmianach. Zwykle do kontrolera interfejsu użytkownika dołącza się obiektObserver
, np. aktywność lub fragment.
Aktualizacja wartości przechowywanej w obiekcie LiveData
aktywuje wszystkich zarejestrowanych obserwatorów, o ile podłączony element LifecycleOwner
jest w stanie aktywnym.
LiveData umożliwia obserwatorom kontrolera interfejsu użytkownika subskrybowanie aktualizacji. Gdy dane w obiekcie LiveData
ulegną zmianie, interfejs automatycznie aktualizuje się w odpowiedzi.
Tworzenie obiektów LiveData
LiveData to kod, którego można używać z dowolnymi danymi, w tym z obiektami z implementacją Collections
, takimi jak List
. Obiekt LiveData
jest zwykle przechowywany w obiekcie ViewModel
i uzyskiwać do niego dostęp za pomocą metody pobierania, jak w tym przykładzie:
Kotlin
class NameViewModel : ViewModel() { // Create a LiveData with a String val currentName: MutableLiveData<String> by lazy { MutableLiveData<String>() } // Rest of the ViewModel... }
Java
public class NameViewModel extends ViewModel { // Create a LiveData with a String private MutableLiveData<String> currentName; public MutableLiveData<String> getCurrentName() { if (currentName == null) { currentName = new MutableLiveData<String>(); } return currentName; } // Rest of the ViewModel... }
Początkowo dane w obiekcie LiveData
nie są ustawione.
Więcej informacji o zaletach i wykorzystaniu klasy ViewModel
znajdziesz w przewodniku po ViewModel.
Obserwowanie obiektów LiveData
W większości przypadków metoda onCreate()
w komponencie aplikacji jest właściwym miejscem do rozpoczęcia obserwacji obiektu LiveData
z tych powodów:
- Pozwala to upewnić się, że system nie wykonuje nadmiarowych wywołań z metody
onResume()
działania lub fragmentu. - Aby zapewnić, że aktywność lub fragment zawiera dane, które mogą wyświetlić się, gdy tylko staną się aktywne. Gdy tylko komponent aplikacji znajdzie się w stanie
STARTED
, otrzyma najnowszą wartość z obserwowanych obiektówLiveData
. Dzieje się tak tylko wtedy, gdy został ustawiony obiektLiveData
do obserwacji.
Ogólnie rzecz biorąc, LiveData dostarcza aktualizacje tylko wtedy, gdy dane się zmienią, i tylko aktywnym obserwatorom. Wyjątek od tej reguły polega na tym, że obserwatorzy otrzymują też aktualizację po przejściu ze stanu nieaktywnego na aktywny. Co więcej, jeśli po raz drugi obserwator zmieni stan z nieaktywnego na aktywny, otrzyma aktualizację tylko wtedy, gdy wartość zmieniła się od czasu ostatniej aktywności.
Poniższy przykładowy kod pokazuje, jak rozpocząć obserwację obiektu LiveData
:
Kotlin
class NameActivity : AppCompatActivity() { // Use the 'by viewModels()' Kotlin property delegate // from the activity-ktx artifact private val model: NameViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Other code to setup the activity... // Create the observer which updates the UI. val nameObserver = Observer<String> { newName -> // Update the UI, in this case, a TextView. nameTextView.text = newName } // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer. model.currentName.observe(this, nameObserver) } }
Java
public class NameActivity extends AppCompatActivity { private NameViewModel model; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Other code to setup the activity... // Get the ViewModel. model = new ViewModelProvider(this).get(NameViewModel.class); // Create the observer which updates the UI. final Observer<String> nameObserver = new Observer<String>() { @Override public void onChanged(@Nullable final String newName) { // Update the UI, in this case, a TextView. nameTextView.setText(newName); } }; // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer. model.getCurrentName().observe(this, nameObserver); } }
Po wywołaniu metody observe()
z parametrem nameObserver
przekazywanym jako parametr obiekt onChanged()
jest natychmiast wywoływany, podając najnowszą wartość zapisaną w obiekcie mCurrentName
.
Jeśli obiekt LiveData
nie ustawił wartości w mCurrentName
, właściwość onChanged()
nie jest wywoływana.
Aktualizowanie obiektów LiveData
LiveData nie ma publicznie dostępnych metod aktualizowania przechowywanych danych. Klasa MutableLiveData
ujawnia metody setValue(T)
i postValue(T)
publicznie. Musisz ich użyć, jeśli chcesz edytować wartość zapisaną w obiekcie LiveData
. Zwykle używany jest w ViewModel
element MutableLiveData
, a potem ViewModel
udostępnia obserwatorom tylko stałe obiekty LiveData
.
Po skonfigurowaniu relacji obserwatora możesz zaktualizować wartość obiektu LiveData
(jak pokazano w tym przykładzie), który będzie wywoływać wszystkich obserwatorów po kliknięciu przycisku:
Kotlin
button.setOnClickListener { val anotherName = "John Doe" model.currentName.setValue(anotherName) }
Java
button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String anotherName = "John Doe"; model.getCurrentName().setValue(anotherName); } });
Wywołanie setValue(T)
w tym przykładzie sprawia, że obserwatorzy wywołują swoje metody onChanged()
z wartością John Doe
. Przykład przedstawia naciśnięcie przycisku, ale funkcja setValue()
lub postValue()
może być wywoływana w celu zaktualizowania mName
z różnych powodów, np. w odpowiedzi na żądanie sieciowe lub wczytanie bazy danych. We wszystkich przypadkach wywołanie setValue()
lub postValue()
aktywuje obserwacje i aktualizuje interfejs.
Używanie LiveData z pokojem
Biblioteka trwałości Room obsługuje obserwowalne zapytania, które zwracają obiekty LiveData
.
Dostrzegalne zapytania są zapisywane w ramach obiektu Database Access Object (DAO).
Room generuje cały kod niezbędny do aktualizacji obiektu LiveData
po aktualizacji bazy danych. W razie potrzeby wygenerowany kod uruchamia zapytanie asynchronicznie w wątku w tle. Przydaje się on do utrzymywania synchronizacji danych wyświetlanych w interfejsie z danymi przechowywanymi w bazie danych. Więcej informacji o salach i atrybucji DAO znajdziesz w przewodniku po bibliotece trwałej w salach.
Używanie współprogramów z LiveData
LiveData
zapewnia obsługę współprogramów Kotlin. Więcej informacji znajdziesz w artykule o używaniu współprogramów Kotlin z komponentami architektury Androida.
LiveData w architekturze aplikacji
LiveData
uwzględnia cykl życia i odpowiada cyklowi życia encji, takich jak działania i fragmenty. LiveData
umożliwia komunikację między tymi właścicielami cyklu życia a innymi obiektami o innym czasie trwania, takimi jak obiekty ViewModel
.
Głównym zadaniem instancji ViewModel
jest wczytywanie danych związanych z interfejsem i zarządzanie nimi, dzięki czemu doskonale nadaje się do przechowywania obiektów LiveData
. Utwórz obiekty LiveData
w ViewModel
i używaj ich do ujawniania stanu w warstwie interfejsu.
Aktywności i fragmenty nie powinny zatrzymywać instancji LiveData
, ponieważ ich rola to wyświetlanie danych, a nie blokowanie stanu. Poza tym uwolnienie działań i fragmentów
do przechowywania danych ułatwia pisanie testów jednostkowych.
Działanie obiektów LiveData
w klasie warstwy danych może być kuszące, ale funkcja LiveData
nie jest przeznaczona do obsługi asynchronicznych strumieni danych. Mimo że możesz to osiągnąć za pomocą przekształceń LiveData
i MediatorLiveData
, to podejście ma wady: możliwość łączenia strumieni danych jest bardzo ograniczona i wszystkie obiekty LiveData
(w tym utworzone za pomocą przekształceń) są obserwowane w wątku głównym. Poniższy kod to przykład tego, jak przytrzymanie LiveData
w Repository
może zablokować wątek główny:
Kotlin
class UserRepository { // DON'T DO THIS! LiveData objects should not live in the repository. fun getUsers(): LiveData<List<User>> { ... } fun getNewPremiumUsers(): LiveData<List<User>> { return getUsers().map { users -> // This is an expensive call being made on the main thread and may // cause noticeable jank in the UI! users .filter { user -> user.isPremium } .filter { user -> val lastSyncedTime = dao.getLastSyncedTime() user.timeCreated > lastSyncedTime } } }
Java
class UserRepository { // DON'T DO THIS! LiveData objects should not live in the repository. LiveData<List<User>> getUsers() { ... } LiveData<List<User>> getNewPremiumUsers() { return Transformations.map(getUsers(), // This is an expensive call being made on the main thread and may cause // noticeable jank in the UI! users -> users.stream() .filter(User::isPremium) .filter(user -> user.getTimeCreated() > dao.getLastSyncedTime()) .collect(Collectors.toList())); } }
Jeśli chcesz używać strumieni danych w innych warstwach aplikacji, rozważ użycie Kotlin Flows, a potem przekonwertowanie ich na LiveData
w ViewModel
za pomocą asLiveData()
.
Więcej informacji o korzystaniu z narzędzia Kotlin Flow
w połączeniu z elementem LiveData
znajdziesz w tym ćwiczeniu w programie.
W przypadku baz kodu utworzonych w Javie rozważ użycie wykonawców w połączeniu z wywołaniami zwrotnymi lub RxJava
.
Rozszerzanie danych LiveData
LiveData uznaje obserwatora w stanie aktywny, jeśli jego cykl życia znajduje się w stanie STARTED
lub RESUMED
. W tym przykładowym kodzie widać, jak rozszerzyć klasę LiveData
:
Kotlin
class StockLiveData(symbol: String) : LiveData<BigDecimal>() { private val stockManager = StockManager(symbol) private val listener = { price: BigDecimal -> value = price } override fun onActive() { stockManager.requestPriceUpdates(listener) } override fun onInactive() { stockManager.removeUpdates(listener) } }
Java
public class StockLiveData extends LiveData<BigDecimal> { private StockManager stockManager; private SimplePriceListener listener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; public StockLiveData(String symbol) { stockManager = new StockManager(symbol); } @Override protected void onActive() { stockManager.requestPriceUpdates(listener); } @Override protected void onInactive() { stockManager.removeUpdates(listener); } }
Implementacja odbiornika cen w tym przykładzie obejmuje następujące ważne metody:
- Metoda
onActive()
jest wywoływana, gdy obiektLiveData
ma aktywnego obserwatora. Oznacza to, że musisz zacząć obserwować zmiany cen akcji za pomocą tej metody. - Metoda
onInactive()
jest wywoływana, gdy obiektLiveData
nie ma aktywnych obserwatorów. Żaden obserwator nie słucha, więc nie ma powodu, żeby pozostawać w kontakcie z usługąStockManager
. - Metoda
setValue(T)
aktualizuje wartość instancjiLiveData
i powiadamia o zmianie wszystkie aktywne obserwatorzy.
Z zajęć StockLiveData
możesz korzystać w następujący sposób:
Kotlin
public class MyFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val myPriceListener: LiveData<BigDecimal> = ... myPriceListener.observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? -> // Update the UI. }) } }
Java
public class MyFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); LiveData<BigDecimal> myPriceListener = ...; myPriceListener.observe(getViewLifecycleOwner(), price -> { // Update the UI. }); } }
Metoda observe()
przekazuje jako pierwszy argument parametr LifecycleOwner
powiązany z widokiem fragmentu. Oznacza to, że ten obserwator jest powiązany z obiektem Lifecycle
powiązanym z właścicielem, co oznacza:
- Jeśli obiekt
Lifecycle
nie jest w stanie aktywnym, obserwator nie zostanie wywołany, nawet jeśli wartość się zmieni. - Po zniszczeniu obiektu
Lifecycle
obserwator jest automatycznie usuwany.
Fakt, że obiekty LiveData
są świadome cyklu życia, oznacza, że można je współdzielić między wieloma aktywnościami, fragmentami i usługami. Aby przykład był prosty, możesz wdrożyć klasę LiveData
jako singleton w ten sposób:
Kotlin
class StockLiveData(symbol: String) : LiveData<BigDecimal>() { private val stockManager: StockManager = StockManager(symbol) private val listener = { price: BigDecimal -> value = price } override fun onActive() { stockManager.requestPriceUpdates(listener) } override fun onInactive() { stockManager.removeUpdates(listener) } companion object { private lateinit var sInstance: StockLiveData @MainThread fun get(symbol: String): StockLiveData { sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol) return sInstance } } }
Java
public class StockLiveData extends LiveData<BigDecimal> { private static StockLiveData sInstance; private StockManager stockManager; private SimplePriceListener listener = new SimplePriceListener() { @Override public void onPriceChanged(BigDecimal price) { setValue(price); } }; @MainThread public static StockLiveData get(String symbol) { if (sInstance == null) { sInstance = new StockLiveData(symbol); } return sInstance; } private StockLiveData(String symbol) { stockManager = new StockManager(symbol); } @Override protected void onActive() { stockManager.requestPriceUpdates(listener); } @Override protected void onInactive() { stockManager.removeUpdates(listener); } }
Można go użyć we fragmencie w następujący sposób:
Kotlin
class MyFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? -> // Update the UI. }) }
Java
public class MyFragment extends Fragment { @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> { // Update the UI. }); } }
Wiele fragmentów i działań może obserwować wystąpienie MyPriceListener
.
LiveData łączy się z usługą systemową tylko wtedy, gdy co najmniej jedna z nich jest widoczna i aktywna.
Przekształć LiveData
Przed wysłaniem go do obserwatorów możesz zmodyfikować wartość przechowywanej w obiekcie LiveData
. Może być też konieczne zwrócenie innej instancji LiveData
w zależności od wartości innej instancji. Pakiet Lifecycle
zawiera klasę Transformations
, która obejmuje metody pomocnicze obsługujące takie scenariusze.
Transformations.map()
- Stosuje funkcję do wartości zapisanej w obiekcie
LiveData
i rozpowszechnia wynik w dół.
Kotlin
val userLiveData: LiveData<User> = UserLiveData() val userName: LiveData<String> = userLiveData.map { user -> "${user.name} ${user.lastName}" }
Java
LiveData<User> userLiveData = ...; LiveData<String> userName = Transformations.map(userLiveData, user -> { user.name + " " + user.lastName });
Transformations.switchMap()
- Podobnie jak
map()
stosuje funkcję do wartości przechowywanej w obiekcieLiveData
oraz wyodrębnia i wysyła wynik w dół. Funkcja przekazana doswitchMap()
musi zwracać obiektLiveData
, tak jak w tym przykładzie:
Kotlin
private fun getUser(id: String): LiveData<User> { ... } val userId: LiveData<String> = ... val user = userId.switchMap { id -> getUser(id) }
Java
private LiveData<User> getUser(String id) { ...; } LiveData<String> userId = ...; LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
Możesz stosować metody przekształcania, aby przenosić informacje przez cały cykl życia obserwatora. Przekształcenia nie są obliczane, dopóki obserwator nie obserwuje zwróconego obiektu LiveData
. Przekształcenia są obliczane w sposób leniwy, dlatego działania związane z cyklem życia są niejawnie przekazywane i nie wymagają dodatkowych jawnych wywołań ani zależności.
Jeśli uważasz, że potrzebujesz obiektu Lifecycle
w obiekcie ViewModel
, lepszym rozwiązaniem będzie przekształcenie. Załóżmy na przykład, że masz komponent interfejsu, który akceptuje adres i zwraca kod pocztowy tego adresu. Możesz zaimplementować naiwną ViewModel
dla tego komponentu w sposób przedstawiony w tym przykładowym kodzie:
Kotlin
class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() { private fun getPostalCode(address: String): LiveData<String> { // DON'T DO THIS return repository.getPostCode(address) } }
Java
class MyViewModel extends ViewModel { private final PostalCodeRepository repository; public MyViewModel(PostalCodeRepository repository) { this.repository = repository; } private LiveData<String> getPostalCode(String address) { // DON'T DO THIS return repository.getPostCode(address); } }
Następnie komponent interfejsu musi wyrejestrować się z poprzedniego obiektu LiveData
i zarejestrować w nowej instancji za każdym razem, gdy wywołuje metodę getPostalCode()
. Poza tym, jeśli komponent interfejsu zostanie odtworzony, aktywuje kolejne wywołanie metody repository.getPostCode()
, zamiast korzystać z wyniku poprzedniego wywołania.
Zamiast tego możesz zastosować wyszukiwanie kodu pocztowego jako przekształcenie wpisanego adresu, jak w tym przykładzie:
Kotlin
class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() { private val addressInput = MutableLiveData<String>() val postalCode: LiveData<String> = addressInput.switchMap { address -> repository.getPostCode(address) } private fun setInput(address: String) { addressInput.value = address } }
Java
class MyViewModel extends ViewModel { private final PostalCodeRepository repository; private final MutableLiveData<String> addressInput = new MutableLiveData(); public final LiveData<String> postalCode = Transformations.switchMap(addressInput, (address) -> { return repository.getPostCode(address); }); public MyViewModel(PostalCodeRepository repository) { this.repository = repository } private void setInput(String address) { addressInput.setValue(address); } }
W tym przypadku pole postalCode
jest zdefiniowane jako przekształcenie kolumny addressInput
. Jeśli w aplikacji ma aktywnego obserwatora powiązanego z polem postalCode
, wartość tego pola jest przeliczana i pobierana po każdej zmianie parametru addressInput
.
Ten mechanizm umożliwia użytkownikom na niższych poziomach aplikacji tworzenie obiektów LiveData
, które są leniwie obliczone na żądanie. Obiekt ViewModel
może łatwo uzyskiwać odwołania do obiektów LiveData
, a następnie określać na ich podstawie reguły przekształcania.
Tworzenie nowych przekształceń
Istnieje kilkanaście różnych przekształceń, które mogą być przydatne w Twojej aplikacji, ale nie są one dostępne domyślnie. Aby wdrożyć własne przekształcenie, możesz użyć klasy MediatorLiveData
, która nasłuchuje innych obiektów LiveData
i przetwarza generowane przez nie zdarzenia. MediatorLiveData
prawidłowo przekazuje swój stan do źródłowego obiektu LiveData
. Więcej informacji o tym wzorcu znajdziesz w dokumentacji klasy Transformations
.
Scal wiele źródeł LiveData
MediatorLiveData
to podklasa klasy LiveData
, która umożliwia scalanie wielu źródeł LiveData. Obserwatorzy obiektów MediatorLiveData
są wyzwalane po każdej zmianie oryginalnego obiektu źródła LiveData.
Jeśli na przykład masz w interfejsie obiekt LiveData
, który można zaktualizować z poziomu lokalnej bazy danych lub sieci, możesz dodać do obiektu MediatorLiveData
te źródła:
- Obiekt
LiveData
powiązany z danymi przechowywanymi w bazie danych. - Obiekt
LiveData
powiązany z danymi, do których uzyskuje się dostęp z sieci.
Twoja aktywność musi tylko obserwować obiekt MediatorLiveData
, aby otrzymywać aktualizacje z obu źródeł. Szczegółowy przykład znajdziesz w sekcji Addendum: exposing
network status (Ujawnianie stanu sieci) Przewodnika po architekturze aplikacji.
Dodatkowe materiały
Więcej informacji o klasie LiveData
znajdziesz w materiałach poniżej.
Próbki
- Sunflower: aplikacja demonstracyjna przedstawiająca sprawdzone metody dotyczące komponentów architektury
- Podstawowy przykład z komponentami architektury Androida
Ćwiczenia z programowania
- Pokój z Androidem z widokiem (Java) (Kotlin)
- Poznaj zaawansowane koordynacje dzięki Kotlin Flow i LiveData
Blogi
- ViewModels i LiveData: Patterns + AntiPatterns
- LiveData spoza modelu ViewModel – wzorce reaktywne z użyciem przekształceń i MediatorLiveData
- LiveData z paskiem SnackBar, nawigacją i innymi zdarzeniami (przypadek SingleLiveEvent)
Filmy
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy JavaScript jest wyłączony
- Używanie współprogramów Kotlin z komponentami uwzględniającymi cykl życia
- Obsługa cyklu życia za pomocą komponentów uwzględniających cykl życia
- Testowanie implementacji stronicowania