Artikelverzeichnis
1. Was ist LiveData?
LiveData
ist eine beobachtbare Datenspeicherklasse.
Im Gegensatz zu regulären beobachtbaren Klassen LiveData
ist sie lebenszyklusbewusst, d. h. sie folgt dem Lebenszyklus anderer Anwendungskomponenten wie Activity
, Fragment
oder . Service
Dieses Bewusstsein stellt sicher, dass LiveData
nur Anwendungskomponentenbeobachter aktualisiert werden, die sich in einem aktiven Lebenszyklusstatus befinden.
Ein Beobachter (dargestellt durch eine Klasse) gilt als aktiv, wenn Observer
seine Lebensdauer im Zustand STARTED
oder liegt. Nur aktive Beobachter werden über Aktualisierungen benachrichtigt. Inaktive Beobachter, die zur Beobachtung des Objekts registriert sind, werden nicht über Änderungen benachrichtigt.RESUMED
LiveData
LiveData
LiveData
LifecycleOwner
Sie können Beobachter gepaart mit Objekten registrieren, die die Schnittstelle implementieren. Wenn diese Beziehung besteht, kann der Beobachter entfernt werden, wenn sich der Zustand des entsprechenden Lifecycle
Objekts ändert . DESTROYED
Dies ist besonders nützlich für Activity
und Fragment
, da sie LiveData
Objekte sicher beobachten können, ohne sich Gedanken über Lecks machen zu müssen (das System meldet sie sofort ab, wenn Activity
ihre Fragment
Lebensdauer zerstört ist).
2. Vorteile von LiveData
Die Verwendung LiveData
hat folgende Vorteile:
-
Stellen Sie sicher, dass die Schnittstelle dem Datenstatus entspricht
LiveData
Folgen Sie dem Beobachtermuster.LiveData
Das **-Objekt wird benachrichtigt , wenn sich die zugrunde liegenden Daten ändernObserver
. Sie können Code zumObserver
Aktualisieren der Schnittstelle in diese Objekte integrieren. Auf diese Weise müssen Sie Ihre Benutzeroberfläche nicht jedes Mal aktualisieren, wenn sich die Daten Ihrer App ändern, da der Beobachter dies für Sie erledigt. -
keine Speicherlecks
Beobachter sind an
Lifecycle
Objekte gebunden und räumen auf, nachdem die zugehörigen Lebenszyklen zerstört wurden. -
Keine Abstürze, wenn die Aktivität beendet wird
Wenn die Lebensdauer des Beobachters inaktiv ist (wie im Backstack
Activity
), ist es nicht gut, Ereignisse zuLiveData
empfangen -
Keine manuelle Bearbeitung von Lebenszyklen mehr
UI-Komponenten beobachten lediglich die relevanten Daten und unterbrechen die Beobachtung nicht oder setzen sie nicht fort.
LiveData
Alle diese Vorgänge werden automatisch verwaltet, da bei der Beobachtung relevante Änderungen des Lebenszyklusstatus berücksichtigt werden. -
Die Daten sind immer aktuell
Wenn ein Lebenszyklus inaktiv wird, erhält er die neuesten Daten, wenn er wieder aktiv wird. Beispielsweise erhält eine Aktivität, die einmal im Hintergrund war, die neuesten Daten, sobald sie wieder in den Vordergrund tritt.
-
Entsprechende Konfigurationsänderungen
Activity
Wenn oder aufgrund einer Konfigurationsänderung, beispielsweise einer Geräterotation, neu erstellt wirdFragment
, erhält es sofort die neuesten verfügbaren Daten. -
Ressource teilen
Sie können das Singleton-Muster verwenden, um
LiveData
Objekte zu erweitern, um Systemdienste zu kapseln, sodass sie anwendungsübergreifend gemeinsam genutzt werden können.LiveData
Das Objekt stellt einmal eine Verbindung zum Systemdienst her, und dann beobachtet jeder Beobachter, der die entsprechende Ressource benötigt, einfachLiveData
das Objekt.
3. Verwenden Sie das LiveData-Objekt
Führen Sie die folgenden Schritte aus, um LiveData
das Objekt zu verwenden:
-
Es wird eine Instanz von erstellt
LiveData
, um bestimmte Datentypen zu speichern. DiesViewModel
geschieht in der Regel im Unterricht. -
Erstellt ein Objekt
onChanged()
, dasObserver
eine Methode definiert, die steuert,LiveData
was passiert, wenn sich die vom Objekt gespeicherten Daten ändern. Normalerweise erstellen SieObserver
Objekte in einem Schnittstellencontroller wie einer Aktivität oder einem Fragment. -
Verwenden Sie
observe()
die Methode, umObserver
das Objekt anLiveData
das Objekt anzuhängen.observe()
Die Methode akzeptiertLifecycleOwner
ein Objekt. DadurchObserver
abonniert das ObjektLiveData
das Objekt, sodass es über Änderungen benachrichtigt wird. Normalerweise hängen SieObserver
Objekte in einem Schnittstellencontroller an, beispielsweise einer Aktivität oder einem Fragment.Hinweis : Sie können
observeForever(Observer)
die Methode verwenden, um einen Beobachter ohne zugehörigesLifecycleOwner
Objekt zu registrieren. In diesem Fall gilt der Beobachter als immer aktiv und wird daher immer über Änderungen benachrichtigt. Sie könnenremoveObserver(Observer)
diese Beobachter entfernen, indem Sie die Methode aufrufen.
Wenn Sie LiveData
den im Objekt gespeicherten Wert aktualisieren, werden alle registrierten Beobachter ausgelöst (sofern der angehängte Wert LifecycleOwner
aktiv ist).
LiveData
Ermöglicht UI-Controller-Beobachtern das Abonnieren von Updates. Wenn LiveData
sich die Daten im Objektspeicher ändern, wird die Schnittstelle automatisch aktualisiert, um zu reagieren.
-
LiveData
Objekt erstellenLiveData
ist ein Wrapper, der für alle Daten verwendet werden kann, einschließlichCollections
implementierter Objekte wieList
.LiveData
Objekte werden normalerweise inViewModel
Objekten gespeichert und über Getter-Methoden darauf zugegriffen, wie im folgenden Beispiel gezeigt: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... }
LiveData
Die Daten im Objekt sind zunächst nicht festgelegt.
Hinweis : Stellen Sie aus folgenden Gründen sicher, dass LiveData
das zum Aktualisieren der Schnittstelle verwendete Objekt im Objekt und nicht in der Aktivität oder dem Fragment gespeichert ist: Vermeiden Sie zu große Aktivitäten und Fragmente. ViewModel
Nun sind diese UI-Controller für die Anzeige von Daten verantwortlich, nicht jedoch für die Speicherung des Datenstatus. Trennen Sie LiveData
die Instanz von einer bestimmten Aktivitäts- oder Fragmentinstanz und ermöglichen Sie LiveData
dem Objekt, Konfigurationsänderungen zu überleben
-
Beobachtungsobjekt
LiveData
_In den meisten Fällen
onCreate()
ist die Methode zum Anbringen einer KomponenteLiveData
aus folgenden Gründen der richtige Ausgangspunkt für die Betrachtung eines Objekts:- Stellen Sie sicher, dass das System keine redundanten Aufrufe von Aktivitäts- oder Fragmentmethoden durchführt
onResume()
. - Stellen Sie sicher, dass die Aktivität oder das Fragment über Daten verfügt, die sofort nach ihrer Aktivierung angezeigt werden können. Sobald sich eine Anwendungskomponente im
STARTED
Status befindet, empfängt sie den neuesten Wert von dem Objekt, das sie beobachtetLiveData
. Dies geschieht nur, wenn ein zu überwachendesLiveData
Objekt festgelegt ist.
Normalerweise sendet LiveData Updates nur, wenn sich die Daten ändern, und nur an aktive Beobachter. Eine Ausnahme von diesem Verhalten besteht darin, dass Beobachter auch Updates erhalten, wenn sie von inaktiv zu aktiv wechseln. Wenn der Beobachter ein zweites Mal von inaktiv auf aktiv wechselt, erhält er außerdem nur Aktualisierungen, wenn sich der Wert seit seiner letzten Aktivierung geändert hat.
Der folgende Beispielcode veranschaulicht, wie mit der Beobachtung von
LiveData
Objekten begonnen wird: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); } }
nameObserver
Wenn es mit dem übergebenen Parameter aufgerufen wirdobserve()
, wird es sofort aufgerufenonChanged()
und stelltmCurrentName
den neuesten in der Datei gespeicherten Wert bereit. Wird nicht aufgerufen, wenn fürLiveData
das Objekt nicht bereits ein Wert festgelegt ist .mCurrentName
onChanged()
- Stellen Sie sicher, dass das System keine redundanten Aufrufe von Aktivitäts- oder Fragmentmethoden durchführt
-
LiveData
Objekt aktualisierenLiveData verfügt über keine öffentlich verfügbaren Methoden zum Aktualisieren gespeicherter Daten.
MutableLiveData
Die Klasse stellt Methoden bereitsetValue(T)
, die verwendet werden müssen,postValue(T)
wenn Sie den im Objekt gespeicherten Wert ändern müssen .LiveData
Wird normalerweise inViewModel
verwendetMutableLiveData
und macht dannViewModel
nur unveränderlicheLiveData
Objekte für Beobachter sichtbar.Nachdem Sie die Beobachterbeziehungen eingerichtet haben, können Sie
LiveData
den Wert des Objekts aktualisieren (wie im folgenden Beispiel), sodass alle Beobachter ausgelöst werden, wenn der Benutzer auf eine Schaltfläche tippt:button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String anotherName = "John Doe"; model.getCurrentName().setValue(anotherName); } });
Der Aufruf in diesem Beispiel setValue(T)
führt dazu, dass der Beobachter John Doe
seine Methode mit dem Wert aufruft onChanged()
. Dieses Beispiel zeigt einen Tastendruck, kann aber auch aus verschiedenen Gründen aufgerufen setValue()
oder postValue()
aktualisiert mName
werden, unter anderem als Reaktion auf eine Netzwerkanfrage oder wenn der Ladevorgang einer Datenbank abgeschlossen ist. In allen Fällen löst der Aufruf setValue()
oder postValue()
den Beobachter aus und aktualisiert die Schnittstelle.
Hinweis : Sie müssen setValue(T)
die Methode aufrufen, um LiveData
das Objekt vom Hauptthread aus zu aktualisieren. Wenn Sie Code in einem Arbeitsthread ausführen, können Sie stattdessen postValue(T)
die Methode verwenden, um LiveData
das Objekt zu aktualisieren.
-
Verwendung
LiveData
mit RoomDie Room- Persistenzbibliothek unterstützt
LiveData
beobachtbare Abfragen, die Objekte zurückgeben. Beobachtbare Abfragen sind Teil von Database Access Objects (DAO).Wenn die Datenbank aktualisiert wird, generiert Room
LiveData
den gesamten Code, der zum Aktualisieren der Objekte erforderlich ist. Der generierte Code führt die Abfrage bei Bedarf asynchron in einem Hintergrundthread aus. Dieses Muster hilft dabei, die in der Benutzeroberfläche angezeigten Daten mit den in der Datenbank gespeicherten Daten synchron zu halten. Weitere Informationen zu Room und DAOs finden Sie im Room Persistence Library Guide .
4. LiveData in der Anwendungsarchitektur
LiveData
Es verfügt über ein Lebenszyklusbewusstsein und folgt dem Lebenszyklus von Entitäten wie und activity
. Sie können Daten zwischen diesen Lebensdauereigentümern und anderen Objekten mit unterschiedlichen Lebensdauern, z. B. Objekten, fragment
übermitteln Die Hauptaufgabe von besteht darin, schnittstellenbezogene Daten zu laden und zu verwalten. Daher eignet es sich sehr gut als alternative Methode zum Persistieren von Objekten. Sie können Objekte erstellen und diese Objekte dann verwenden, um den Status für die UI-Ebene bereitzustellen.LiveData
ViewModel
ViewModel
LiveData
ViewModel
LiveData
activity
und fragment
sollten keine Instanzen beibehalten, LiveData
da ihr Zweck darin besteht, Daten anzuzeigen und nicht den Status zu halten. Außerdem erleichtert es das Schreiben von Unit-Tests, indem Aktivitäten und Fragmente persistent gemacht werden, ohne dass Daten persistent bleiben.
Sie könnten versucht sein, Objekte in Ihren Datenschichtklassen zu verwenden LiveData
, diese LiveData
sind jedoch nicht gut für die Verarbeitung asynchroner Datenströme geeignet. Sie können zwar LiveData
Transformationen verwenden, MediatorLiveData
um dies zu erreichen, die Nachteile dieses Ansatzes bestehen jedoch darin, dass die Funktionalität zum Kombinieren von Datenströmen sehr begrenzt ist und alle LiveData
Objekte (einschließlich der durch Transformationen erstellten) im Hauptthread beobachtet werden. Hier ist ein Beispielcode, der zeigt , wie Repository
das Beibehalten in LiveData
einem den Hauptthread blockiert:
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()));
}
}
Wenn Sie den Datenfluss in anderen Ebenen Ihrer App verwenden müssen, ziehen Sie die Verwendung von Kotlin Flow in Betracht und konvertieren Sie dann Kotlin Flow in die Verwendung asLiveData()
in . Erfahren Sie in diesem Codelab mehr über die Verwendung von Kotlin mit Kotlin . Erwägen Sie für in Java erstellte Codebasen die Verwendung von Executoren mit Rückrufen oder .ViewModel
LiveData
Flow
LiveData
RxJava
5. LiveData erweitern
Ein Beobachter gilt als aktiv, wenn seine Lebensdauer im STARTED
oder- RESUMED
Zustand ist. LiveData
Der folgende Beispielcode veranschaulicht, wie LiveData
eine Klasse erweitert wird:
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);
}
}
Die Price-Listener-Implementierung in diesem Beispiel umfasst die folgenden wichtigen Methoden:
LiveData
Die Methode wird aufgerufen, wenn das Objekt aktive Beobachter hatonActive()
. Das bedeutet, dass Sie mit dieser Methode beginnen müssen, Aktienkursaktualisierungen zu beobachten.LiveData
Die Methode wird aufgerufen, wenn das Objekt keine aktiven Beobachter hatonInactive()
. Da keine Beobachter zuhören, gibt es keinen Grund,StockManager
die Verbindung zum Dienst aufrechtzuerhalten.setValue(T)
Die Methode aktualisiertLiveData
den Wert der Instanz und benachrichtigt aktive Beobachter über die Änderung.
Sie können StockLiveData
die Klasse wie folgt verwenden:
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.
});
}
}
observe()
Der Methode wird Fragment
die zugehörige Ansicht LifecycleOwner
als erster Parameter übergeben. Dadurch wird angezeigt, dass dieser Beobachter an das mit dem Eigentümer verknüpfte Objekt gebunden ist Lifecycle
, was bedeutet:
- Wenn
Lifecycle
das Objekt nicht aktiv ist, wird der Beobachter nicht aufgerufen, selbst wenn sich der Wert ändert. Lifecycle
Beobachter werden automatisch entfernt, wenn das Objekt zerstört wird .
LiveData
Die Tatsache, dass Objekte lebenszyklusbewusst sind, bedeutet, dass Sie diese Objekte zwischen mehreren und teilen Activity
können . Um das Beispiel einfach zu halten, können Sie die Klasse wie folgt als Singleton implementieren:Fragment
Service
LiveData
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);
}
}
und Sie können Fragment
es im Inneren wie folgt verwenden:
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.
});
}
}
Mehrere Fragment
und Activity
beobachtbare MyPriceListener
Instanzen. LiveData
Stellen Sie eine Verbindung zu einem oder mehreren Systemdiensten nur her, wenn diese sichtbar und aktiv sind .
6. LiveData konvertieren
Möglicherweise möchten Sie LiveData
Änderungen an den im Objekt gespeicherten Werten vornehmen, bevor Sie es an Beobachter senden, oder Sie müssen möglicherweise eine andere LiveData
Instanz basierend auf dem Wert einer anderen Instanz zurückgeben. Lifecycle
Das Paket stellt Transformations
die Klasse bereit, die Hilfsmethoden für diese Situationen enthält.
Transformations.map()
LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
user.name + " " + user.lastName
});
-
Transformations.switchMap()
Ähnlich
map()
wie wendet eine Funktion auf den imLiveData
Objekt gespeicherten Wert an und entpackt das Ergebnis und sendet es weiter. Eine an übergebene FunktionswitchMap()
muss ein Objekt zurückgebenLiveData
, wie im folgenden Beispiel gezeigt:
private LiveData<User> getUser(String id) {
...;
}
LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
Sie können die Übergangsmethode verwenden, um Informationen während der Lebensdauer des Beobachters zu übermitteln. LiveData
Transformationen werden nicht ausgewertet, es sei denn, ein Beobachter beobachtet das zurückgegebene Objekt. Da Übergänge träge berechnet werden, wird lebenszyklusbezogenes Verhalten implizit ohne zusätzliche explizite Aufrufe oder Abhängigkeiten weitergegeben.
Wenn Sie der Meinung sind, dass Sie ein Objekt innerhalb eines Objekts ViewModel
benötigen Lifecycle
, ist eine Konvertierung möglicherweise die bessere Lösung. Angenommen, Sie verfügen über eine Schnittstellenkomponente, die eine Adresse entgegennimmt und die Postleitzahl für diese Adresse zurückgibt. Sie können für diese Komponente eine einfache Implementierung implementieren ViewModel
, wie im folgenden Beispielcode gezeigt:
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);
}
}
Die Schnittstellenkomponente muss dann bei jedem Aufruf die Registrierung des vorherigen LiveData
Objekts aufheben und sich bei der neuen Instanz registrieren. getPostalCode()
Wenn die UI-Komponente neu erstellt wird, löst sie außerdem einen weiteren repository.getPostCode()
Aufruf der Methode aus, anstatt das Ergebnis des vorherigen Aufrufs zu verwenden.
Sie können eine Postleitzahlensuche auch als Transformation einer Adresseingabe implementieren, wie im folgenden Beispiel gezeigt:
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);
}
}
In diesem Fall postalCode
werden die Felder als addressInput
Transformationen von definiert. Solange Ihrer App postalCode
ein aktiver Beobachter mit dem Feld zugeordnet ist, wird der Feldwert addressInput
bei jeder Änderung neu berechnet und abgerufen.
Dieser Mechanismus ermöglicht es Anwendungen auf niedrigerer Ebene, Objekte zu erstellen, die bei Bedarf träge berechnet werden LiveData
. ViewModel
Objekte können leicht LiveData
Referenzen auf Objekte erhalten und dann darauf basierende Transformationsregeln definieren.
Es gibt ein Dutzend verschiedener spezifischer Transformationen, die in Ihrer App nützlich sein könnten, aber sie werden nicht standardmäßig bereitgestellt. MediatorLiveData
Um Ihre eigenen Transformationen zu implementieren, können Sie die Klasse verwenden , die auf andere LiveData
Objekte lauscht und von ihnen ausgegebene Ereignisse verarbeitet. MediatorLiveData
Gibt seinen Zustand LiveData
korrekt an das Quellobjekt weiter. Weitere Informationen zu diesem Muster finden Sie in Transformations
der Referenzdokumentation für die Klasse.
7. Führen Sie mehrere LiveData-Quellen zusammen
MediatorLiveData
Ist LiveData
eine Unterklasse, die es Ihnen ermöglicht, mehrere LiveData
Quellen zu kombinieren. Der Beobachter für das Objekt wird immer dann ausgelöst, wenn sich eines der ursprünglichen LiveData
Quellobjekte ändert MediatorLiveData
.
Wenn Ihre Schnittstelle beispielsweise ein Objekt enthält, das über eine lokale Datenbank oder das Netzwerk aktualisiert werden kann LiveData
, können Sie MediatorLiveData
dem Objekt die folgende Quelle hinzufügen:
- Objekte , die mit in der Datenbank gespeicherten Daten verknüpft sind
LiveData
. - Ein Objekt , das mit Daten verknüpft ist, auf die über das Netzwerk zugegriffen wird
LiveData
.
Ihre Aktivität MediatorLiveData
kann Aktualisierungen von beiden Quellen erhalten, indem Sie einfach das Objekt beobachten.