Різниця setValue () & postValue () у MutableLiveData


107

Існує два шляхи, які дозволяють змінити значення MutableLiveData. Але в чому різниця між setValue()& postValue()in MutableLiveData.

Я не зміг знайти документацію на те саме.

Ось клас MutableLiveDataAndroid.

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

Відповіді:


179

На підставі документації:

setValue () :

Встановлює значення. Якщо є активні спостерігачі, значення буде надіслано їм. Цей метод потрібно викликати з основного потоку.

postValue () :

Опублікує завдання в основному потоці для встановлення заданого значення. Якщо ви викликали цей метод кілька разів, перш ніж основний потік виконував опубліковане завдання, буде відправлено лише останнє значення.

Підводячи підсумок, ключовою різницею буде:

setValue()метод повинен бути викликаний з основного потоку. Але якщо вам потрібно встановити значення з фонового потоку, postValue()слід використовувати.


"буде відправлено лише останнє значення". Я не можу бути впевнений у цьому, прочитавши код. Отже, здається, що коли перший потік збирається потрапити до внутрішнього синхронізованого блоку всередині postValue (), наступне вікно процесора може бути потенційно передане потоку 2, який публікує інше значення. Потік 2 може потім завершити синхронізований блок, і планувальник видає першому потоку вікно для запуску. Тепер він замінює те, що вже написано в потоці 2. Чи можливо це?
stdout

98

Усі наведені вище відповіді є правильними. Але ще одна важлива відмінність. Якщо ви телефонуєте postValue()на поле, яке не має спостерігачів, і після цього ви телефонуєте getValue(), ви не отримаєте значення, яке ви встановили postValue(). Тож будьте обережні, якщо працюєте у фоновому режимі без спостерігачів.


3
Якби я міг потроїти голос! Виходячи з цього, здається, найкраще використовувати, setValue()якщо це можливо, і обережно використовувати 'postValue ()', лише коли це необхідно. Дякую
jungledev

1
Ні, тут немає жодного "найкращого" способу. Якщо ви працюєте з LiveData з фонового потоку, вам слід використовувати postValue. Також в останній версії компонентів життєвого циклу це виправлено ... можливо.
w201

"Також у останній версії компонентів життєвого циклу це виправлено ... можливо." Чи є у вас більше інформації щодо цього? Дякую
Кріс Невілл,

1
Я провів кілька тестів і, здається, з останньою версією lib все працює як слід.
w201

Не могли б ви показати мені наведений вище конкретно код? Якщо у ViewModel я реалізував like noObserveLiveData.postValue("sample"), In Activity, коли використовував getValue типу viewModel.noObserveLiveData.getValueЧи ви маєте на увазі, чи не це значення я встановив у postValue () ("зразок")?
kwmt

14

setValue()викликається безпосередньо з потоку абонента, синхронно повідомляє спостерігачів і LiveDataнегайно змінює значення. Його можна викликати лише з MainThread.
postValue()використовує всередині чогось подібного new Handler(Looper.mainLooper()).post(() -> setValue()), тому виконується setValueчерез HandlerMainThread. Її можна викликати з будь-якої нитки.


11

setValue()

Встановлює значення. Якщо є активні спостерігачі, значення буде надіслано їм.

Цей метод потрібно викликати з основного потоку .

postValue

Якщо вам потрібно встановити значення з фонового потоку, ви можете використовувати postValue(Object)

Опублікує завдання в основному потоці для встановлення заданого значення.

Якщо ви викликали цей метод кілька разів, перш ніж основний потік виконував опубліковане завдання, буде відправлено лише останнє значення.


5

Це не пряма відповідь на вищезазначену проблему. Відповіді від Сагара та w201 чудові. Але простим емпіричним правилом, яке я використовую у ViewModels для MutableLiveData, є:

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

Замініть mutValна бажане значення.


Приємно, мені це подобається. У Kotlin я створив розширення, яке інкапсулює інтелектуальне оновлення, тому численні оновлення цінностей у моєму додатку - це один послідовний дзвінок.
19Craig

4

setValue()метод повинен бути викликаний з основного потоку. Якщо вам потрібно встановити значення з фонового потоку, ви можете використовувати postValue().

Більше тут .


0

У нашому додатку ми використовували одну LiveData, яка містить дані для декількох переглядів на дії / екрані. В основному N кількість наборів даних для N кількість переглядів. Це нас трохи занепокоїло, оскільки спосіб, на який призначений postData. І в LD є об’єкт стану, який передає, щоб переглянути, який вигляд потрібно оновити.

так LD виглядає так:

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

Є кілька подань (view_1 та view_2), які потрібно було оновити, коли відбувається одна подія .. означає, що вони повинні отримувати сповіщення одночасно, коли подія відбувається. Отже, я зателефонував:

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

Це не спрацювало б з відомих нам причин.

Я зрозумів, що в основному одна LD повинна представляти лише одну точку зору. Тоді немає шансів, що вам доведеться викликати postData () двічі поспіль. Навіть якщо ви телефонуєте, спосіб, на який postData обробляє це для вас, - це те, що ви також очікували (відображаючи найсвіжіші дані для вас). Все добре стає на свої місця.

Один LD -> один вигляд. ІДЕАЛЬНО

Один LD -> декілька поглядів МОЖЕ БУТИ ДИВНА ПОВЕДІНКА

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.