Разница между setValue () и postValue () в MutableLiveData


115

Есть два способа изменить значение 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);
    }
}

Ответы:


192

На основании документации:

setValue () :

Устанавливает значение. Если есть активные наблюдатели, значение будет отправлено им. Этот метод необходимо вызывать из основного потока.

postValue () :

Отправляет задачу в основной поток, чтобы установить заданное значение. Если вы вызываете этот метод несколько раз до того, как основной поток выполнит опубликованную задачу, будет отправлено только последнее значение.

Подводя итог, ключевое различие будет заключаться в следующем:

setValue()метод должен вызываться из основного потока. Но если вам нужно установить значение из фонового потока, postValue()следует использовать.


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

104

Все ответы верны. Но еще одно важное отличие. Если вы вызываете postValue()поле, в котором нет наблюдателей, а после этого вызываете getValue(), вы не получаете значение, которое вы установили postValue(). Так что будьте осторожны, если вы работаете в фоновых потоках без наблюдателей.


4
Хотел бы я получить тройной голос! Исходя из этого, кажется, что лучше использовать, setValue()если возможно, и осторожно использовать postValue () только при необходимости. Спасибо
jungledev 06

1
Нет, здесь нет «лучшего» способа. Если вы работаете со своими LiveData из фонового потока, вам следует использовать postValue. Также в последней версии компонентов жизненного цикла это исправлено ... возможно.
w201

«Также в последней версии компонентов жизненного цикла это исправлено ... вероятно». У вас есть дополнительная информация по этому поводу? Спасибо
Крис Невилл

1
Провел несколько тестов и кажется, что с последней версией библиотеки все работает как надо.
w201

Не могли бы вы показать мне приведенный выше конкретный код? Если в ViewModel я реализовал как в noObserveLiveData.postValue("sample")действии, когда я использовал getValue, например, viewModel.noObserveLiveData.getValueВы имеете в виду Разве это не то значение, которое я установил в postValue () ("sample")?
kwmt

15

setValue()вызывается непосредственно из вызывающего потока, синхронно уведомляет наблюдателей и LiveDataнемедленно изменяет значение. Его можно вызвать только из MainThread.
postValue()использует внутри что - то вроде этого new Handler(Looper.mainLooper()).post(() -> setValue()), так что он работает setValueчерез Handlerв MainThread. Его можно вызвать из любого потока.


11

setValue()

Устанавливает значение. Если есть активные наблюдатели, значение будет отправлено им.

Этот метод необходимо вызывать из основного потока .

postValue

Если вам нужно установить значение из фонового потока, вы можете использовать postValue(Object)

Отправляет задачу в основной поток, чтобы установить заданное значение.

Если вы вызываете этот метод несколько раз до того, как основной поток выполнит опубликованную задачу, будет отправлено только последнее значение.


6

Это не прямой ответ на указанную выше проблему. Ответы Сагара и 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.