webentwicklung-frage-antwort-db.com.de

So aktualisieren Sie LiveData eines ViewModel über den Hintergrunddienst und die Update-Benutzeroberfläche

Kürzlich untersuche ich Android Architektur, die kürzlich von Google eingeführt wurde. Aus der Dokumentation habe ich Folgendes herausgefunden:

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 der Funktion loadUsers() rufe ich die Daten asynchron ab, wobei ich zuerst die Datenbank (Room) auf diese Daten überprüfen werde

  2. Wenn ich dort keine Daten erhalte, rufe ich die API auf, 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 der empfohlene Ansatz, um dies zu tun?

Wenn ich ein Service starte, um die API von der loadUsers() -Methode aufzurufen, wie kann ich die MutableLiveData<List<User>> users - Variable von dieser Service aktualisieren?

68
CodeCameo

Ich gehe davon aus, dass Sie Android-Architekturkomponenten verwenden. Eigentlich ist es egal, wo Sie service, asynctask or handler Aufrufen, um die Daten zu aktualisieren. Sie können die Daten aus dem Dienst oder aus der asynchronen Aufgabe mit der Methode postValue(..) einfügen. Deine Klasse würde so aussehen:

private void loadUsers() {
    // do async operation to fetch users and use postValue() method
    users.postValue(listOfData)
}

Da die usersLiveData ist, ist die Room -Datenbank dafür verantwortlich, Benutzerdaten dort bereitzustellen, wo sie eingefügt werden.

Note: In einer MVVM-ähnlichen Architektur ist das Repository hauptsächlich für das Überprüfen und Abrufen von lokalen Daten und Remotedaten verantwortlich.

68

Bitte verwenden Sie die postValue (..) -Methode von Live-Daten aus dem Hintergrund-Thread.

private void loadUsers() {
    // do async operation to fetch users and use postValue() method
   users.postValue(listOfData)
}
41
minhazur

... in der Funktion loadUsers () rufe ich die Daten asynchron ab ... Wie kann ich die Variable MutableLiveData> users von diesem Dienst aktualisieren, wenn ich einen Dienst starte, um die API über die Methode loadUsers () aufzurufen?

Wenn die App Benutzerdaten in einem Hintergrund-Thread abruft, ist postValue (anstelle von setValue ) hilfreich.

In der loadData-Methode gibt es einen Verweis auf das MutableLiveData-Objekt "users". Die loadData-Methode ruft auch einige neue Benutzerdaten ab (z. B. ein Repository).

Wenn sich die Ausführung in einem Hintergrundthread befindet, wird MutableLiveData.postValue () außerhalb der Beobachter des MutableLiveData-Objekts aktualisiert.

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);        
        }
    });

}
15
albert c braun

Schauen Sie sich das Android Architecture Guide an, das den neuen Architekturmodulen wie LiveData und ViewModel beiliegt. Sie diskutieren genau dieses Thema ausführlich.

In ihren Beispielen stellen 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 ausführlichere Beispiele, einschließlich der Übermittlung des Netzwerkstatus, der Meldung von Fehlern usw.

4
user1978019

https://developer.Android.com/topic/libraries/architecture/guide.html

Hat sehr gute Antworten auf Ihr Problem. Scrollen Sie ganz nach unten, um zu sehen, wie Sie die Antwort in Ihrer Datenbank speichern und die Benutzeroberfläche mithilfe von LiveData aktualisieren können.

enter image description here

2
Prakash

Wenn Sie Ihre API im Repository aufrufen,

In 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;
}

In ViewModel

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

In 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 hier Java_1.8 Lambda verwenden, können Sie es auch ohne verwenden.

1
Shubham Agrawal