Unterschied von setValue () & postValue () in MutableLiveData

103

Es gibt zwei Möglichkeiten, wie Sie den Wert von ändern können MutableLiveData. Aber was ist der Unterschied zwischen setValue()& postValue()in MutableLiveData.

Ich konnte keine Dokumentation dafür finden.

Hier ist Klasse MutableLiveDatavon Android.

package android.arch.lifecycle;

/**
 * {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method.
 *
 * @param <T> The type of data hold by this instance
 */
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}
Khemraj
quelle

Antworten:

176

Basierend auf der Dokumentation:

setValue () :

Legt den Wert fest. Wenn es aktive Beobachter gibt, wird der Wert an sie gesendet. Diese Methode muss vom Hauptthread aufgerufen werden.

postValue () :

Sendet eine Aufgabe an einen Hauptthread, um den angegebenen Wert festzulegen. Wenn Sie diese Methode mehrmals aufgerufen haben, bevor ein Hauptthread eine gepostete Aufgabe ausgeführt hat, wird nur der letzte Wert gesendet.

Zusammenfassend wäre der Hauptunterschied:

setValue()Methode muss vom Hauptthread aufgerufen werden. Wenn Sie jedoch einen Wert aus einem Hintergrundthread festlegen müssen, postValue()sollte dieser verwendet werden.

Sagar
quelle
"Nur der letzte Wert wird versendet". Ich kann mir nicht sicher sein, wenn ich den Code lese. Sobald der erste Thread den inneren synchronisierten Block in postValue () erreicht, scheint das nächste CPU-Fenster möglicherweise dem Thread 2 zugewiesen zu werden, der einen anderen Wert veröffentlicht. Thread 2 kann dann den synchronisierten Block vervollständigen und der Scheduler gibt dem ersten Thread ein Fenster, um sich selbst auszuführen. Jetzt wird überschrieben, was Thread 2 bereits geschrieben hat. Ist das möglich?
Stdout
93

Alle obigen Antworten sind richtig. Aber noch ein wichtiger Unterschied. Wenn Sie postValue()ein Feld aufrufen , das keine Beobachter hat, und danach anrufen getValue(), erhalten Sie nicht den Wert, den Sie festgelegt haben postValue(). Seien Sie also vorsichtig, wenn Sie in Hintergrund-Threads ohne Beobachter arbeiten.

w201
quelle
3
Ich wünschte, ich könnte dreifach abstimmen! Auf dieser Grundlage scheint es am besten zu sein, setValue()wenn möglich und 'postValue ()' nur bei Bedarf vorsichtig zu verwenden. Danke
jungledev
1
Nein, hier ist kein "bester" Weg. Wenn Sie mit Ihren LiveData aus dem Hintergrund-Thread arbeiten, sollten Sie postValue verwenden. Auch in der neuesten Version von Lifecycle-Komponenten wurde es behoben ... wahrscheinlich.
w201
"Auch in der neuesten Version von Lifecycle-Komponenten wurde es behoben ... wahrscheinlich." Haben Sie weitere Informationen dazu? Vielen Dank
Chris Nevill
1
Ich habe einige Tests durchgeführt und es scheint, dass mit der letzten Version von lib alles so funktioniert, wie es sollte.
w201
Können Sie mir den obigen konkreten Code zeigen? Wenn ich in ViewModel wie noObserveLiveData.postValue("sample")In Activity implementiert habe , als ich getValue verwendet viewModel.noObserveLiveData.getValuehabe, meinen Sie, ist es nicht der Wert, den ich in postValue () ("sample") festgelegt habe?
Kwmt
13

setValue()wird direkt vom Aufrufer-Thread aufgerufen, benachrichtigt Beobachter synchron und ändert den LiveDataWert sofort. Es kann nur von MainThread aufgerufen werden.
postValue()verwendet in so etwas new Handler(Looper.mainLooper()).post(() -> setValue()), so läuft es setValueüber Handlerin MainThread. Es kann von jedem Thread aufgerufen werden.

Ufkoku
quelle
10

setValue()

Legt den Wert fest. Wenn es aktive Beobachter gibt, wird der Wert an sie gesendet.

Diese Methode muss vom Hauptthread aufgerufen werden .

postValue

Wenn Sie einen Wert aus einem Hintergrundthread festlegen müssen, können Sie diesen verwenden postValue(Object)

Sendet eine Aufgabe an einen Hauptthread, um den angegebenen Wert festzulegen.

Wenn Sie diese Methode mehrmals aufgerufen haben, bevor ein Hauptthread eine gepostete Aufgabe ausgeführt hat, wird nur der letzte Wert gesendet.

Nilesh Rathod
quelle
5

Dies ist keine direkte Antwort auf das oben genannte Problem. Die Antworten von Sagar und w201 sind fantastisch. Eine einfache Faustregel, die ich in ViewModels für MutableLiveData verwende, lautet jedoch:

private boolean isMainThread() {
    return Looper.myLooper() == Looper.getMainLooper();
}

private MutableLiveData<Boolean> mutVal = new MutableLiveData<>(false);
public LiveData<Boolean> getMutVal() { return this.mutVal;  }
public void setMutVal(boolean val) {
    if (isMainThread()) mutVal.setValue(val);
    else mutVal.postValue(val);
}

Ersetzen Sie mutValdurch Ihren gewünschten Wert.

Himujjal Upadhyaya
quelle
Schön, das gefällt mir. In Kotlin habe ich eine Erweiterung erstellt, die das Smart Update kapselt, sodass die zahlreichen Wertaktualisierungen in meiner App ein einziger, konsistenter Aufruf sind.
19Craig
4

setValue()Methode muss vom Hauptthread aufgerufen werden. Wenn Sie einen Wert aus einem Hintergrundthread festlegen müssen, können Sie diesen verwenden postValue().

Mehr hier .

Levon Petrosyan
quelle
0

In unserer App haben wir einzelne LiveData verwendet, die Daten für mehrere Ansichten in einer Aktivität / einem Bildschirm enthalten. Grundsätzlich N Anzahl Datensätze für N Anzahl Ansichten. Dies hat uns ein wenig beunruhigt, weil die Art und Weise, wie postData entwickelt wurde. Und wir haben ein Statusobjekt in LD, das anzeigt, welche Ansicht aktualisiert werden muss.

LD sieht also so aus:

LD {
   state (view_1, view_2, view_3 …),
   model_that_contains_data_of_all_views
}

Es gibt einige Ansichten (view_1 und view_2), die aktualisiert werden mussten, wenn ein Ereignis eintritt. Dies bedeutet, dass sie gleichzeitig benachrichtigt werden sollten, wenn ein Ereignis eintritt. Also rief ich an:

postData(LD(view_1, data))
postData(LD(view_2, data)

Dies würde aus uns bekannten Gründen nicht funktionieren.

Was ich verstanden habe ist, dass im Grunde eine LD nur eine Ansicht darstellen sollte. Dann besteht keine Chance, dass Sie postData () zweimal hintereinander aufrufen müssen. Selbst wenn Sie anrufen, ist die Art und Weise, wie postData für Sie damit umgeht, genau das, was Sie auch erwarten würden (die neuesten Daten werden für Sie angezeigt). Alles passt gut zusammen.

Eine LD -> eine Ansicht. PERFEKT

Eine LD -> mehrere Ansichten Es kann ein seltsames Verhalten geben

cgr
quelle