MutableLiveData 中 setValue() 和 postValue() 的区别

Difference of setValue() & postValue() in MutableLiveData

MutableLiveData有两种改变值的方法。但是 setValue()postValue()MutableLiveData.

之间有什么区别

我找不到相同的文档。

这里是classMutableLiveData,共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);
    }
}

基于文档:

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()

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().

更多here.

setValue() 直接从调用者线程调用,同步通知观察者并立即更改 LiveData 值。它只能从 MainThread 调用。
postValue() 在内部使用类似 new Handler(Looper.mainLooper()).post(() -> setValue()) 的内容,因此它在 MainThread 中通过 Handler 运行 setValue。它可以从任何线程调用。

以上答案全部正确。但还有一个更重要的区别。如果您调用 postValue(),然后调用 getValue(),您 可能不会 收到您在 postValue() 中设置的值。如果主线程已经设置了该值,那么您将获得您发布的值,但如果主线程尚未设置该值,那么您将不会获得您发布的值。因此,如果您在后台线程中工作,请小心。

这不是上述问题的直接答案。 and 的回答很棒。但我在 MutableLiveData 的 ViewModels 中使用的一个简单经验法则是:

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 替换为您想要的值。

在我们的应用中,我们使用了单个 LiveData,其中包含 activity/screen 中多个视图的数据。基本上 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

TL;博士

  • 如果您在主线程上工作,那么 setValue 和 postValue 将以相同的方式工作,即它们将更新值并通知观察者。
  • 如果在某些后台线程中工作,则不能使用 setValue。你必须在这里与一些观察者一起使用 postValue 。 更多here

如果设置该值需要很长时间(例如,如果您必须从响应速度可能很慢的远程源检索其他数据),请使用 postValue() 这样您就不会锁定主线程。

当保证快速设置值时(通常如此),setValue() 是最简单和最好的。

postValue - 可以在任何地方使用

setValue - 仅来自 main/UI 线程

基本上,postValue 应该只在后台线程中使用,因为它可能比 setValue 慢,后者反应更快。

我写了一个片段来处理这两种情况:

/**
 * Live data thread-safe set-value
 * Context: 
*/
fun <T> MutableLiveData<T>.assignValue(newValue: T){

    if(Looper.myLooper() == Looper.getMainLooper()) {
        this.value = newValue
    }
    else {
        this.postValue(newValue)
    }
}