为什么有一个单独的MutableLiveData子类来扩展LiveData?

106

看起来 MutableLiveDataLiveData 的区别仅在于将 setValue()postValue() 方法公开,而在 LiveData 中它们是受保护的。

为什么要为此更改创建一个单独的类,而不是在 LiveData 中直接定义这些方法为公共方法呢?

一般来说,这种继承形式(仅增加某些方法的可见性)是一个众所周知的实践吗?有哪些情景可以使其变得有用(假设我们可以访问所有代码)?


12
这是一个设计决策。LiveData是不可变的,因为客户端无法更改其内部状态,因此具有线程安全性。 - Blackbelt
4个回答

151
LiveData - Android Developer Documentation 中,您可以看到对于LiveDatasetValue()postValue() 方法不是公共的。而在MutableLiveData - Android Developer Documentation中,您可以看到MutableLiveData 在内部扩展了LiveData,并且LiveData的两个重要方法公开使用。它们是setValue()postValue()setValue():设置值并将其分派给所有活动观察者,必须从主线程调用。 postValue() :将任务发布到主线程以覆盖setValue()设置的值,必须从后台线程调用。
因此,LiveData不可变的MutableLiveDataLiveData,它是可变的线程安全的

50
LiveData 并非完全不可变,只是不能在 ViewModel 以外的类中进行修改。ViewModel 类可以随意对其进行修改(例如定时器 ViewModel)。如果希望在 ViewModel 以外的类中修改它,则需要使用 MutableLiveData。 - Elliptica
2
让我们来看一个场景,一个使用仓库模式(服务器+Room)的应用程序,其中Room是唯一的数据源。应用程序只从Room获取数据,而Room从服务器获取更新。由于服务器的数据会更新Room的数据,因此必须使用mutableLiveData吗?或者能使用LiveData呢? - Dr4ke the b4dass
7
LiveData是抽象的,因此您不能直接创建LiveData对象而不进行扩展。MutableLiveData扩展了LiveData。 - Serdar Samancıoğlu
1
LiveData和MutableLiveData的链接指向已弃用的文档。为什么当我建议使用实际链接进行编辑时,它被拒绝了呢? - Daniel
1
@Daniel 不确定为什么其他审阅者在审阅队列中拒绝了它。我已经批准了这个更改,谢谢! :) - Sneh Pandya
显示剩余4条评论

15

以下是完整的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进行封装。 即使您在ViewModel类中有MutableLiveData进行操作,您也可以将LiveData暴露给Fragment / Activity(UI Controller)。

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

这样,您的UI控制器只能观察值而无法编辑它们。显然,您的UI控制器可以使用TempViewModel的公共方法(例如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

5

MutableLiveData 是 LiveData 的子类,LiveData 的受保护方法只能由自身或其子类访问。因此,在这种情况下,MutableLiveData 作为 LiveData 的子类可以访问这些受保护的方法。

你想要做的事情是观察一个实例并查看是否有任何更改。但与此同时,你不希望任何“外部人员”更改你正在观察的实例。在某种意义上,这会创建一个问题,因为你想要一个既可变又不可变的对象,以更新任何新状态,并且不可变,以确保任何不应该更新此实例的人都不能更改它。这两个功能冲突,但可以通过创建额外的层来解决。

所以你需要扩展 LiveData 类,并添加一个能够访问其方法的类。这个子层级,在这种情况下就是 MutableLiveData,能够访问其父类的受保护方法。

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

现在技巧几乎完成。你只公开 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(...)

引言 一般而言,这种继承形式(只增加某些方法的可见性)是一种众所周知的实践,有哪些场景可以使用它呢(假设我们可以访问所有代码)?

是的,这很常见,上述描述是一个常见的场景。移除观察者模式,仅以设置/获取的形式来实现同样可以从中受益。当然,最后取决于你在哪里实现它,没有硬性规定。


-3
LiveData和MutableLiveData是Android Jetpack中用于以生命周期感知的方式管理数据的两个类。它们都是可观察的,这意味着可以监听它们的数据变化。然而,这两个类之间存在一些关键区别:
LiveData是不可变的。这意味着无法直接更改LiveData对象的值。相反,您必须使用新值创建一个新的LiveData对象。这有助于防止数据损坏,并使得更容易理解应用程序的状态。 MutableLiveData是可变的。这意味着可以直接更改MutableLiveData对象的值。这在需要根据用户输入或其他事件更新数据的情况下非常有用。然而,需要谨慎使用MutableLiveData,因为如果使用不正确,可能会导致数据损坏。 通常情况下,当您想要创建一个不可变的数据源时,应该使用LiveData。这是LiveData最常见的用例。当您需要能够直接更改数据时,应该使用MutableLiveData。这种情况较少见,但在某些情况下很有用。
自动生命周期管理 是 是 用例 创建一个不可变的数据源 直接更新数据
希望对您有所帮助!如果您有任何其他问题,请随时告诉我。

2
本站不欢迎AI生成的答案。请参阅https://meta.stackoverflow.com/questions/421831/temporary-policy-chatgpt-is-banned。 - Eric Aya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接