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

Есть два способа изменить значение MutableLiveData. Но в чем разница между setValue() и postValue() в MutableLiveData.

Мне не удалось найти документацию по тому же самому.

Вот класс MutableLiveData 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);
    }
}
135
0
61 528
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

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

setValue ():

Sets the value. If there are active observers, the value will be dispatched to them. This method must be called from the main thread.

postValue ():

Posts a task to a main thread to set the given value. If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.

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

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

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

stdout 17.07.2019 17:58

ВАЖНОЕ ПРИМЕЧАНИЕ. Я только что заметил, что если вы находитесь в основном потоке и используете postValue, для отправки данных потребуется несколько миллисекунд по сравнению с setValue. У меня такое случалось, когда я заполнял макет вручную, с setValue это было мгновенно, но не с публикацией

TootsieRockNRoll 27.01.2021 13:47

setValue()

Sets the value. If there are active observers, the value will be dispatched to them.

This method must be called from the main thread.

postValue

If you need set a value from a background thread, you can use postValue(Object)

Posts a task to a main thread to set the given value.

If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.

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

Подробнее здесь.

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

Спасибо за хороший ответ. Итак, согласно ответу @w201 (если он действителен до сих пор), метод Handlerpost не вызывается, если он не является основным потоком и нет наблюдателя?

starriet 13.01.2021 03:01

post всегда вызывается, а значение обновляется внутри LiveData. Но если наблюдателей нет или они не в запущенном состоянии, они не будут уведомлены.

Ufkoku 13.01.2021 10:32

Основная проблема заключается в том, что значение поста обновляется асинхронно, поэтому, если вы вызвали getValue (), вы можете получить старую

Ufkoku 13.01.2021 10:51

Итак, если я позвоню getValue(), я могу получить старое значение, но, может быть, я смогу получить последнее значение, верно? Итак, w201 сказал в своем ответе, что "вы не получаете значение, которое вы установили в postValue ()", но, может быть, я смогу получить значение, которое я установил?

starriet 13.01.2021 13:26

@starriet да, вы можете получить значение, установленное postValue (). Все дело в параллелизме. Если у основного потока достаточно времени для выполнения обновления, инициированного postValue (), тогда getValue () вернет опубликованный. Если вы вызываете getValue () слишком рано после postValue () и у основного потока не было времени выполнить опубликованное обновление, тогда getValue () вернет старое значение.

Ufkoku 13.01.2021 20:09

Итак, если я правильно понял, установка значения не имеет ничего общего с существованием наблюдателей. Даже если наблюдателя нет, после того, как рабочий поток отправил какое-то значение с помощью postValue(), если, основной поток выполняет установку значения, тогда мы можем получить значение, которое мы отправили. Пожалуйста, дайте мне знать, если я ошибаюсь. Большое спасибо :)

starriet 14.01.2021 03:06

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

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

jungledev 06.12.2018 16:03

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

w201 14.12.2018 18:19

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

Chris Nevill 17.01.2019 18:04

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

w201 19.01.2019 09:28

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

kwmt 16.09.2019 15:20

@ w201, когда вы сказали "с последней версией библиотеки все работает как надо", означает ли это, что ваш ответ больше не действителен? ... Итак, теперь мы МОЖЕМ получить значение, которое мы установили в postValue(...), даже если нет наблюдателей? Если это так, я думаю, нам следует изменить этот ответ, чтобы люди не запутались.

starriet 13.01.2021 02:49

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

В нашем приложении мы использовали одну 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 обработает это за вас, вы также ожидаете (отображение последних данных для вас). Все хорошо встало на свои места.

One LD -> one View. PERFECT

One LD -> multiple views THERE MAY BE A WEIRD BEHAVIOR

Другие вопросы по теме