So aktualisieren Sie LiveData eines ViewModel vom Hintergrunddienst und aktualisieren die Benutzeroberfläche

Lesezeit: 6 Minuten

Benutzer-Avatar
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:

  1. in dem loadUsers() Funktion rufe ich die Daten asynchron ab, wobei ich zuerst die Datenbank (Raum) auf diese Daten überprüfen werde

  2. Wenn ich die Daten dort nicht erhalte, mache ich einen API-Aufruf, um die Daten vom Webserver abzurufen.

  3. 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

    – 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

Benutzer-Avatar
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


Benutzer-Avatar
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 zurück … wie konvertiere ich das LiveData in ein MutableLiveData?

    – Kilokahn

    21. Juli 2018 um 23:33 Uhr


  • Ich glaube nicht, dass das DAO von Room wirklich dazu gedacht ist, mit MutableLiveData-Objekten umzugehen. Das DAO benachrichtigt Sie über eine Änderung an der zugrunde liegenden Datenbank, aber wenn Sie den Wert in der Datenbank ändern möchten, rufen Sie die Methoden des DAO auf. Vielleicht ist auch die Diskussion hier nützlich: stackoverflow.com/questions/50943919/…

    – Albert C. Braun

    22. Juli 2018 um 3:25 Uhr

  • Werfen Sie einen Blick auf die Leitfaden zur Android-Architektur das begleitet die neuen Architekturmodule wie LiveData und ViewModel. Sie diskutieren genau dieses Thema eingehend.

    In ihren Beispielen setzen sie es nicht in einen Dienst. Schauen Sie sich an, wie sie es mit einem „Repository“-Modul und Retrofit lösen. Die Anhänge unten enthalten vollständigere Beispiele, einschließlich der Übermittlung des Netzwerkstatus, der Meldung von Fehlern usw.

    Wenn Sie Ihre API dann im Repository aufrufen,

    Im Repository:

    public MutableLiveData<LoginResponseModel> checkLogin(LoginRequestModel loginRequestModel) {
        final MutableLiveData<LoginResponseModel> data = new MutableLiveData<>();
        apiService.checkLogin(loginRequestModel)
                .enqueue(new Callback<LoginResponseModel>() {
                    @Override
                    public void onResponse(@NonNull Call<LoginResponseModel> call, @Nullable Response<LoginResponseModel> response) {
                        if (response != null && response.isSuccessful()) {
                            data.postValue(response.body());
                            Log.i("Response ", response.body().getMessage());
                        }
                    }
    
                    @Override
                    public void onFailure(@NonNull Call<LoginResponseModel> call, Throwable t) {
                        data.postValue(null);
                    }
                });
        return data;
    }
    

    Im ViewModel

    public LiveData<LoginResponseModel> getUser() {
        loginResponseModelMutableLiveData = repository.checkLogin(loginRequestModel);
        return loginResponseModelMutableLiveData;
    }
    

    Im Aktivität/Fragment

    loginViewModel.getUser().observe(LoginActivity.this, loginResponseModel -> {
            if (loginResponseModel != null) {
                Toast.makeText(LoginActivity.this, loginResponseModel.getUser().getType(), Toast.LENGTH_SHORT).show();
            }
        });
    

    Hinweis: Wenn Sie JAVA_1.8 Lambda hier verwenden, können Sie ohne es verwenden

    1324350cookie-checkSo aktualisieren Sie LiveData eines ViewModel vom Hintergrunddienst und aktualisieren die Benutzeroberfläche

    This website is using cookies to improve the user-friendliness. You agree by using the website further.

    Privacy policy