为什么有单独的LiveData子类MutableLiveData子类?


96

看起来MutableLiveDataLiveData仅通过公开setValue()postValue()方法有所不同,而LiveData它们却受到保护。

有什么理由为此更改创建一个单独的类,而不是简单地将这些方法LiveData本身定义为公共方法?

一般来说,这种继承形式(增加某些方法的可见性是唯一的更改)是否是众所周知的做法,并且在某些情况下它可能有用(假设我们可以访问所有代码)?


10
这是一个设计决定。LiveData是不可变的,因为客户端无法更改内部状态,因此线程安全
Blackbelt

Answers:


137

LiveData - Android开发者文档,你可以看到,对于LiveDatasetValue()postValue()方法不是公共的。

然而,在MutableLiveData - Android开发者文档,你可以看到,MutableLiveData扩展LiveData内部也的两大神奇的方法LiveData公开提供这一点,他们setValue()postValue()

setValue():设置值并将其分发给所有活动的观察者,必须从主线程调用。

postValue():将任务发布到主线程以覆盖设置的值setValue(),必须从后台线程调用。

因此,LiveData一成不变的MutableLiveDataLiveData它是可变的线程安全的


36
LiveData并不是不可变的,只是不能在ViewModel类之外进行修改。ViewModel类可以根据需要进行修改(例如,计时器ViewModel)。如果要在ViewModel类之外进行修改,可以使用MutableLiveData。
Elliptica

2
让我们以这种情况为例,该应用程序具有存储库模式(服务器+会议室),其中会议室是事实的唯一来源。应用仅从Room获取数据,而Room从服务器获取数据。是否必须使用mutableLiveData,因为可以使用服务器更新Room或LiveData中的数据?
Dr4ke the b4dass

5
LiveData是抽象的,因此您不能直接创建LiveData对象而不对其进行扩展。MutableLiveData扩展了LiveData。
SerdarSamancıoğlu18年

1
指向LiveData和MutableLiveData的链接直接指向不推荐使用的文档。为什么当我建议使用实际链接进行编辑时却被拒绝了?
丹尼尔(Daniel)

1
@Daniel不知道为什么它被审阅队列中的其他审阅人拒绝。我已经批准了更改,谢谢!:)
斯内潘迪亚

9

这是整个MutableLiveData.java文件:

package androidx.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);
    }
}

因此,是的,区别仅在于公开postValuesetValue公开。

我能想到的一个用例是使用Kotlin中的Backing Property进行封装。您可以暴露LiveData你的碎片/活动(UI控制器),即使你可以MutableLiveData在你的操控ViewModel类。

    class TempViewModel : ViewModel() {
        ...
        private val _count = MutableLiveData<Int>()
        val count: LiveData<Int>
            get() = _count
        public fun incrementCount() = _count.value?.plus(1)
        ...
    }

这样,您的UI控制器将只能观察值而不能对其进行编辑。显然,您的UI控制器可以使用TempViewModellike的公共方法来编辑值 incrementCount()

注意:为了澄清可变/不变的混淆-

data class User(var name: String, var age: Int)

class DemoLiveData: LiveData<User>()

var demoLiveData: LiveData<User>? = DemoLiveData()

fun main() {
    demoLiveData?.value = User("Name", 23) // ERROR
    demoLiveData?.value?.name = "Name" // NO ERROR
    demoLiveData?.value?.age = 23  // NO ERROR
}

什么_score
IgorGanapolsky

0

MutableLiveData从LiveData扩展。LiveData的受保护方法只能通过自身或子类来解决。因此,在这种情况下,作为LiveData子类的MutableLiveData可以访问这些受保护的方法。

您想要做的是观察实例并查看是否有任何更改。但是同时,您不希望任何“外部人员”更改您正在观察的实例。从某种意义上讲,这会带来问题,因为您希望拥有一个可更改的对象,以更新任何新状态,而不是不可更改,以确保没有人不能更新此实例。这两个功能相互冲突,但是可以通过创建额外的图层来解决。

因此,您要做的是使用可以访问其方法的类扩展LiveData类。子层(在这种情况下为MutableLiveData)能够访问其父级(/超级)的受保护方法。

现在开始创建实例,并创建MutableLiveData的观察者实例。同时,您创建一个引用该实例的LiveData实例。因为MutableLiveData扩展了LiveData,所以任何MutableLiveData实例都是LiveData对象,因此可以由LiveData变量引用。

现在,the俩几乎完成了。您只公开LiveData实例,没有人可以使用其受保护的方法,也不能将其强制转换为它的超级实例(也许在编译时,但不会运行:运行时错误)。而且您将实际的子类实例保持私有,因此只有拥有实例的人员才能使用实例的方法对其进行更改。

//create instance of the sub class and keep this private
private val _name: MutableLiveData<String> = MutableLiveData<String>()
//create an instance of the super class referring to the same instance
val name: LiveData<String> = _name
//assign observer to the super class, being unable to change it
name.value.observe(.....)

现在,超类通知何时应用任何更改。

//change the instance by using the sub class
_name.postValue(...)
//or _name.setValue(...)

Blockquote一般来说,这种继承形式(增加某些方法的可见性是唯一的更改)是一种众所周知的做法吗?在某些情况下它可能有用(假设我们可以访问所有代码)?

是的,这是众所周知的,上面描述的是一种常见的情况。删除观察者模式,仅以set / get形式进行设置就可以从中受益。取决于执行它的位置,最后没有黄金法则。

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.