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


105

有两种方法可以使的变化值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);
    }
}

Answers:


178

根据文档:

setValue()

设置值。如果有活动的观察者,那么值将分派给他们。必须从主线程调用此方法。

postValue()

将任务发布到主线程以设置给定值。如果在主线程执行发布的任务之前多次调用此方法,则只会分派最后一个值。

总而言之,关键区别在于:

setValue()方法必须从主线程调用。但是,如果需要从后台线程设置值,postValue()则应使用。


“将仅分派最后一个值”。我无法通过阅读代码确定这一点。这样看来,一旦第一个线程即将到达postValue()内部的内部同步块,就可以将下一个CPU窗口分配给正在发布另一个值的线程2。然后,线程2可以完成同步的块,并且调度程序为第一个线程提供运行自身的窗口。现在,它覆盖了线程2已经编写的内容。这可能吗?
stdout

96

以上所有答案都是正确的。但是还有一个重要的区别。如果您调用postValue()没有观察者的字段,然后再调用getValue(),则不会收到在其中设置的值postValue()。因此,如果您在没有观察员的情况下使用后台线程,请当心。


3
希望我能三票赞成!基于此,似乎最好是setValue()尽可能使用它,并且仅在必要时谨慎使用“ postValue()”。谢谢
jungledev

1
不,这不是任何“最佳”方法。如果您从后台线程处理LiveData,则应使用postValue。同样在生命周期组件的最新版本中,它可能已修复。
w201

“还可以在最新版本的生命周期组件中对其进行修复……”。您还有其他信息吗?谢谢
克里斯·内维尔

1
我进行了一些测试,似乎在lib的最新版本中一切正常。
w201

您能告诉我上面的具体代码吗?如果在ViewModel中,我像noObserveLiveData.postValue("sample")在Activity中那样实现,当我在使用getValue时,就像viewModel.noObserveLiveData.getValue您是说,这是否不是我在postValue()中设置的值(“样本”)吗?
kwmt19年

14

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


11

setValue()

设置值。如果有活动的观察者,那么值将分派给他们。

必须从主线程调用此方法

postValue

如果需要从后台线程设置值,则可以使用 postValue(Object)

将任务发布到主线程以设置给定值。

如果在主线程执行发布的任务之前多次调用此方法,则只会分派最后一个值。


5

这不是上述问题的直接答案。Sagarw201的答案都很棒。但是我在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中,我创建了一个扩展,其中封装了智能更新,因此整个应用程序中的众多价值更新都是一个一致的调用。
克雷格,


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为您处理数据的方式也将是您期望的(在视图中显示最新数据)。一切都准备就绪。

1个LD-> 1个视图。完善

一个LD->多个视图可能会有奇怪的行为

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.