Разница 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);
}
}
10 ответов
На основании документации:
Устанавливает значение. Если есть активные наблюдатели, значение будет отправлено им. Этот метод должен вызываться из основного потока.
Отправляет задачу в основной поток, чтобы установить заданное значение. Если вы вызывали этот метод несколько раз до того, как основной поток выполнил опубликованную задачу, было отправлено только последнее значение.
Подводя итог, ключевое отличие будет:
setValue()
метод должен быть вызван из основного потока. Но если вам нужно установить значение из фонового потока, postValue()
должен быть использован.
Все вышеприведенные ответы верны. Но еще одно важное отличие. Если вы позвоните postValue()
на поле, которое не имеет наблюдателей, и после этого вы звоните getValue()
, вы не получите значение, которое вы установили в postValue()
, Так что будьте осторожны, если вы работаете в фоновых потоках без наблюдателей.
setValue()
вызывается напрямую из потока вызывающего и синхронно уведомляет наблюдателей. Также его можно вызывать только из MainThread.postValue()
использует внутри что-то вроде этого new Handler(Looper.mainLooper()).post(() -> setValue())
так работает setValue
с помощью Handler
в MainThread. Также его можно вызвать из любого потока.
setValue()
Устанавливает значение. Если есть активные наблюдатели, значение будет отправлено им.
Этот метод должен вызываться из основного потока.
postValue
Если вам нужно установить значение из фонового потока, вы можете использовать
postValue(Object)
Отправляет задачу в основной поток, чтобы установить заданное значение.
Если вы вызывали этот метод несколько раз до того, как основной поток выполнил опубликованную задачу, было отправлено только последнее значение.
Это не прямой ответ на указанную выше проблему. Ответы Сагара и 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
с желаемым значением.
setValue()
метод должен быть вызван из основного потока. Если вам нужно установить значение из фонового потока, вы можете использовать postValue()
,
Больше здесь.
postValue - можно использовать откуда угодно
setValue - только из основного потока/потока пользовательского интерфейса
По сути, postValue следует использовать только из фонового потока, так как он может быть медленнее по сравнению с setValue, который реагирует быстрее.
Я написал фрагмент, который обрабатывает оба случая:
/**
* Live data thread-safe set-value
* Context: https://stackoverflow.com/a/52227632/6688493
*/
fun <T> MutableLiveData<T>.assignValue(newValue: T){
if(Looper.myLooper() == Looper.getMainLooper()) {
this.value = newValue
}
else {
this.postValue(newValue)
}
}
TL; DR
- Если вы работаете в основном потоке, то и setValue, и postValue будут работать одинаково, т.е. они обновят значение и уведомят наблюдателей.
- Если вы работаете в фоновом потоке, вы не можете использовать setValue. Здесь вы должны использовать postValue с некоторым наблюдателем. Подробнее здесь
Если установка значения займет много времени (например, если вам нужно получить дополнительные данные из удаленного источника, который может медленно отвечать), используйте postValue(), чтобы не блокировать основной поток.
Когда установка значения гарантированно будет быстрой (как это чаще всего и бывает), setValue() является самым простым и лучшим.
В нашем приложении мы использовали одну 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 -> несколько просмотров МОЖЕТ БЫТЬ СТРАННЫМ ПОВЕДЕНИЕМ