Różnica setValue () i postValue () w MutableLiveData


113

Istnieją dwa sposoby, aby zmienić wartość MutableLiveData. Ale jaka jest różnica między setValue()& postValue()in MutableLiveData.

Nie mogłem znaleźć dokumentacji dla tego samego.

Oto klasa MutableLiveDataAndroida.

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

Odpowiedzi:


191

Na podstawie dokumentacji:

setValue () :

Ustawia wartość. Jeśli istnieją aktywni obserwatorzy, wartość zostanie do nich wysłana. Ta metoda musi być wywołana z głównego wątku.

postValue () :

Wysyła zadanie do głównego wątku, aby ustawić daną wartość. Jeśli wywołasz tę metodę wiele razy, zanim główny wątek wykonał opublikowane zadanie, wysłana zostanie tylko ostatnia wartość.

Podsumowując, kluczową różnicą byłoby:

setValue()metodę należy wywołać z głównego wątku. Ale jeśli potrzebujesz ustawić wartość z wątku w tle, postValue()należy użyć.


„wysłana zostanie tylko ostatnia wartość”. Nie mogę być tego pewien, czytając kod. Wygląda więc na to, że gdy pierwszy wątek ma trafić w wewnętrzny zsynchronizowany blok wewnątrz postValue (), następne okno procesora może zostać potencjalnie przekazane wątkowi 2, który wysyła inną wartość. Wątek 2 może wtedy zakończyć zsynchronizowany blok, a program planujący daje pierwszemu wątkowi okno do samodzielnego uruchomienia. Teraz zastępuje to, co już napisał wątek 2. czy to możliwe?
— stdout

103

Wszystkie powyższe odpowiedzi są prawidłowe. Ale jeszcze jedna ważna różnica. Jeśli zadzwonisz postValue()na pole, które nie ma obserwatorów, a następnie zadzwonisz getValue(), nie otrzymasz wartości, którą ustawiłeś postValue(). Dlatego zachowaj ostrożność, jeśli pracujesz w tle bez obserwatorów.


3
Chciałbym móc zagłosować trzykrotnie za! Na tej podstawie wydaje się, że najlepiej jest używać, setValue()jeśli to możliwe, i ostrożnie używać metody „postValue ()” tylko wtedy, gdy jest to konieczne. Dzięki
— jungledev

1
Nie, tutaj nie ma żadnego „najlepszego” sposobu. Jeśli pracujesz z LiveData z wątku w tle, powinieneś użyć postValue. Również w najnowszej wersji komponentów cyklu życia zostało to naprawione ... prawdopodobnie.
— w201

„Również w najnowszej wersji komponentów cyklu życia to naprawiło ... prawdopodobnie.” Czy masz więcej informacji na ten temat? Dzięki
— Chris Nevill

1
Zrobiłem kilka testów i wygląda na to, że w ostatniej wersji lib wszystko działa tak, jak powinno.
— w201

Czy możesz mi pokazać konkretnie powyższy kod? Jeśli w ViewModel, zaimplementowałem w ten sposób noObserveLiveData.postValue("sample"), w działaniu, kiedy użyłem metody getValue w stylu viewModel.noObserveLiveData.getValueCzy masz na myśli Czy to nie jest wartość, którą ustawiłem w postValue () ("sample")?
— kwmt

15

setValue()jest wywoływana bezpośrednio z wątku wywołującego, synchronicznie powiadamia obserwatorów i LiveDatanatychmiast zmienia wartość. Można go wywołać tylko z MainThread.
postValue()używa wewnątrz czegoś takiego new Handler(Looper.mainLooper()).post(() -> setValue()), więc działa setValueprzez HandlerMainThread. Można go wywołać z dowolnego wątku.


11

setValue()

Ustawia wartość. Jeśli istnieją aktywni obserwatorzy, wartość zostanie do nich wysłana.

Ta metoda musi być wywołana z głównego wątku .

postValue

Jeśli potrzebujesz ustawić wartość z wątku w tle, możesz użyć postValue(Object)

Wysyła zadanie do głównego wątku, aby ustawić daną wartość.

Jeśli wywołasz tę metodę wiele razy, zanim główny wątek wykonał opublikowane zadanie, wysłana zostanie tylko ostatnia wartość.


6

Nie jest to bezpośrednia odpowiedź na powyższy problem. Odpowiedzi udzielone przez Sagar i w201 są niesamowite. Ale prosta zasada, której używam w ViewModels dla MutableLiveData, to:

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

Zastąp mutValżądaną wartością.


Fajnie, podoba mi się to. W Kotlin stworzyłem rozszerzenie, które zawiera inteligentną aktualizację, dzięki czemu liczne aktualizacje wartości w całej mojej aplikacji są jednym, spójnym połączeniem.
— 19Craig

4

setValue()metodę należy wywołać z głównego wątku. Jeśli potrzebujesz ustawić wartość z wątku w tle, możesz użyć postValue().

Więcej tutaj .


0

W naszej aplikacji użyliśmy pojedynczych danych LiveData, które zawierają dane z wielu widoków na aktywności / ekranie. Zasadniczo N liczba zbiorów danych dla N liczba widoków. Trochę nas to zaniepokoiło, ponieważ sposób, w jaki postData jest przeznaczony. I mamy obiekt stanu w LD, który przekazuje pogląd o tym, który widok należy zaktualizować.

więc LD wygląda tak:

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

Istnieje kilka widoków (widok_1 i widok_2), które musiały zostać zaktualizowane, gdy wystąpi jedno zdarzenie… oznacza, że ​​powinny otrzymać powiadomienie w tym samym czasie, gdy wystąpi zdarzenie. Więc zadzwoniłem:

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

To nie zadziała z powodów, które znamy.

Zrozumiałem, że zasadniczo jeden LD powinien reprezentować tylko jeden pogląd. Wtedy nie ma szans, żebyś musiał wywołać postData () dwa razy z rzędu. Nawet jeśli zadzwonisz, sposób, w jaki postData obsługuje to za Ciebie, jest tym, czego również byś się spodziewał (pokazując najnowsze dane w widoku). Wszystko jest na swoim miejscu.

Jeden LD -> jeden widok. IDEALNY

Jeden LD -> wiele widoków MOŻE BYĆ DZIWNE ZACHOWANIE

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.