So aktualisieren Sie LiveData eines ViewModel vom Hintergrunddienst und aktualisieren die Benutzeroberfläche
Lesezeit: 6 Minuten
S. Haque
Vor kurzem erkunde ich die Android-Architektur, die kürzlich von Google eingeführt wurde. Von dem Dokumentation Ich habe das gefunden:
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<Users>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// do async operation to fetch users
}
}
Die Aktivität kann wie folgt auf diese Liste zugreifen:
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
Meine Frage ist, ich werde dies tun:
in dem loadUsers() Funktion rufe ich die Daten asynchron ab, wobei ich zuerst die Datenbank (Raum) auf diese Daten überprüfen werde
Wenn ich die Daten dort nicht erhalte, mache ich einen API-Aufruf, um die Daten vom Webserver abzurufen.
Ich werde die abgerufenen Daten in die Datenbank (Raum) einfügen und die Benutzeroberfläche entsprechend den Daten aktualisieren.
Was ist die empfohlene Vorgehensweise, um dies zu tun?
Wenn ich ein beginne Service um die API von der aufzurufen loadUsers() Methode, wie kann ich die aktualisieren MutableLiveData<List<User>> users davon variabel Service?
Zunächst fehlt Ihnen ein Repository. Ihr ViewModel sollte keine Datenladeaufgaben ausführen. Abgesehen davon muss Ihr Dienst, da Sie Room verwenden, die LiveData im ViewModel nicht direkt aktualisieren. Der Service kann nur Daten in Room einfügen, während Ihre ViewModelData nur an Room angehängt werden sollten und Updates von Room erhalten (nachdem der Service Daten eingefügt hat). Aber für die absolut beste Architektur sehen Sie sich die Implementierung der NetworkBoundResource-Klasse unten auf dieser Seite an: developer.android.com/topic/libraries/architecture/guide.html
– Marko Gajić
28. Mai 2017 um 16:35 Uhr
danke für den vorschlag 🙂
– S Haque
29. Mai 2017 um 15:24 Uhr
Die Repositor-Klasse wird in den offiziellen Dokumenten, die ROOM oder die Android-Architekturkomponenten beschreiben, nicht erwähnt
Die Funktion loadUsers() Im Grunde wird das Repo aufgerufen, um die Benutzerinformationen zu erhalten
– S Haque
23. September 2018 um 5:23 Uhr
androidcodehunter
Ich gehe davon aus, dass Sie verwenden Komponenten der Android-Architektur. Eigentlich ist es egal, wo Sie anrufen service, asynctask or handler um die Daten zu aktualisieren. Sie können die Daten aus dem Dienst oder aus der Asynctask mit einfügen postValue(..) Methode. Ihre Klasse würde so aussehen:
private void loadUsers() {
// do async operation to fetch users and use postValue() method
users.postValue(listOfData)
}
Als die users ist LiveData, Room Die Datenbank ist dafür verantwortlich, Benutzerdaten bereitzustellen, wo immer sie eingefügt werden.
Note: In einer MVVM-ähnlichen Architektur ist das Repository hauptsächlich für das Überprüfen und Abrufen lokaler Daten und entfernter Daten verantwortlich.
Ich erhalte “java.lang.IllegalStateException: Cannot access database on the main thread since it” beim Aufrufen meiner db-Methoden wie oben. Können Sie sagen, was falsch sein könnte?
– Prashant
1. August 2017 um 9:33 Uhr
Ich verwende Evernote-Job, der die Datenbank im Hintergrund aktualisiert, während ich auf der Benutzeroberfläche bin. Aber LiveData wird nicht aktualisiert
– Akshay Chordiya
12. Februar 2018 um 11:58 Uhr
users.postValue(mUsers); -> Aber kann die postValue-Methode von MutableLiveData LiveData akzeptieren???
– Cheok Yan Cheng
1. April 2018 um 21:42 Uhr
Mein Fehler war die Verwendung value Anstatt von postValue. Danke für deine Antwort.
– Hesam
20. Juli 2018 um 3:53 Uhr
@pcj Sie müssen entweder die Raumoperation in einem Thread durchführen oder Operationen im Hauptthread aktivieren – googlen Sie nach weiteren Antworten.
– Kilokahn
23. Juli 2018 um 18:56 Uhr
minhazur
Sie können verwenden MutableLiveData<T>.postValue(T value) Methode aus dem Hintergrundthread.
private void loadUsers() {
// do async operation to fetch users and use postValue() method
users.postValue(listOfData)
}
Zur Erinnerung: postValue() ist in LiveData geschützt, aber öffentlich in MutableLiveData
– Langer Ranger
29. September 2017 um 6:52 Uhr
diese Arbeit auch aus einer Hintergrundaufgabe und in Situationen, in denen .setValue() wäre nicht erlaubt
– davejoem
11. August 2020 um 22:47 Uhr
… in der Funktion loadUsers() rufe ich die Daten asynchron ab … Wenn ich einen Dienst starte, um die API von der Methode loadUsers() aufzurufen, wie kann ich dann die MutableLiveData>-Benutzervariable von diesem Dienst aktualisieren?
Wenn die App Benutzerdaten in einem Hintergrundthread abruft, postValue (statt setValue) wird nützlich sein.
In der Methode loadData gibt es einen Verweis auf das Objekt MutableLiveData “users”. Die loadData-Methode ruft auch einige neue Benutzerdaten von irgendwoher ab (z. B. einem Repository).
Wenn nun die Ausführung in einem Hintergrund-Thread erfolgt, aktualisiert MutableLiveData.postValue() externe Beobachter des MutableLiveData-Objekts.
Vielleicht so etwas:
private MutableLiveData<List<User>> users;
.
.
.
private void loadUsers() {
// do async operation to fetch users
ExecutorService service = Executors.newSingleThreadExecutor();
service.submit(new Runnable() {
@Override
public void run() {
// on background thread, obtain a fresh list of users
List<String> freshUserList = aRepositorySomewhere.getUsers();
// now that you have the fresh user data in freshUserList,
// make it available to outside observers of the "users"
// MutableLiveData object
users.postValue(freshUserList);
}
});
}
Repository getUsers() -Methode könnte eine API für die Daten aufrufen, die asynchron sind (möglicherweise einen Dienst oder eine asynchrone Aufgabe dafür starten). Wie kann sie in diesem Fall die Liste aus ihrer Rückgabeanweisung zurückgeben?
– S Haque
9. Juni 2017 um 6:15 Uhr
Vielleicht könnte es das LiveData-Objekt als Argument verwenden. (Etwas wie repository.getUsers(users)). Dann würde die Repository-Methode users.postValue selbst aufrufen. Und in diesem Fall würde die loadUsers-Methode nicht einmal einen Hintergrund-Thread benötigen.
– Albert C. Braun
9. Juni 2017 um 17:35 Uhr
Vielen Dank für die Antwort …. ich verwende jedoch eine Raumdatenbank zur Speicherung und das DAO gibt ein LiveData
Zunächst fehlt Ihnen ein Repository. Ihr ViewModel sollte keine Datenladeaufgaben ausführen. Abgesehen davon muss Ihr Dienst, da Sie Room verwenden, die LiveData im ViewModel nicht direkt aktualisieren. Der Service kann nur Daten in Room einfügen, während Ihre ViewModelData nur an Room angehängt werden sollten und Updates von Room erhalten (nachdem der Service Daten eingefügt hat). Aber für die absolut beste Architektur sehen Sie sich die Implementierung der NetworkBoundResource-Klasse unten auf dieser Seite an: developer.android.com/topic/libraries/architecture/guide.html
– Marko Gajić
28. Mai 2017 um 16:35 Uhr
danke für den vorschlag 🙂
– S Haque
29. Mai 2017 um 15:24 Uhr
Die Repositor-Klasse wird in den offiziellen Dokumenten, die ROOM oder die Android-Architekturkomponenten beschreiben, nicht erwähnt
– Jono
22. Februar 2018 um 10:56 Uhr
Repository ist eine empfohlene Best Practice für Codetrennung und -architektur, sehen Sie sich dieses Beispiel an: codelabs.developers.google.com/codelabs/…
– glisu
22. September 2018 um 14:24 Uhr
Die Funktion
loadUsers()
Im Grunde wird das Repo aufgerufen, um die Benutzerinformationen zu erhalten– S Haque
23. September 2018 um 5:23 Uhr