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

Ale*_*tin 63 oop android android-livedata android-architecture-components

它看起来MutableLiveData不同于LiveData仅将the setValue()postValue()方法公开,而在LiveData它们受到保护的情况下.

为这种变化创建一个单独的类的原因是什么,而不是简单地将这些方法定义为公共的LiveData

一般来说,这种继承形式(增加某些方法的可见性是唯一的变化)是一种众所周知的做法,以及它可能有用的一些场景(假设我们可以访问所有代码)?

Sne*_*dya 99

LiveData - Android开发人员文档中,您可以看到for LiveData,setValue()&postValue()methods不是公共的.

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

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

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

所以,LiveData不可改变的.MutableLiveDataLiveData它是可变的线程安全的.

  • 并不是说LiveData是不可变的,只是不能在ViewModel类的_outside_上修改它。ViewModel类可以根据需要进行修改(例如,计时器ViewModel)。如果要在ViewModel类之外进行修改,可以使用MutableLiveData。 (14认同)
  • LiveData是抽象的,因此您无法在不扩展的情况下直接创建LiveData对象.MutableLiveData扩展了LiveData. (3认同)
  • 让我们以这种情况为例,该应用程序具有存储库模式(服务器+会议室),其中会议室是事实的唯一来源。应用仅从Room获取数据,而Room从服务器获取数据。是否必须使用mutableLiveData,因为可以使用服务器更新Room或LiveData中的数据? (2认同)

Ana*_*nth 14

这是整个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);
    }
}
Run Code Online (Sandbox Code Playgroud)

所以是的,区别只在于制作postValuesetValue公开。

我能回忆起来的一个用例是使用Kotlin 中的支持属性进行封装。LiveData即使您可以MutableLiveDataViewModel类中进行操作,您也可以向 Fragment/Activity(UI 控制器)公开。

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

这样您的 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
}
Run Code Online (Sandbox Code Playgroud)


Kha*_*een 5

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

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

因此,您要做的就是使用可以访问其方法的类来扩展 LiveData 类。子层(在本例中为 MutableLiveData)能够访问其父层 (/super) 的受保护方法。

现在您开始创建实例,并创建 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
Run Code Online (Sandbox Code Playgroud)
//assign observer to the super class, being unable to change it
name.value.observe(.....)
Run Code Online (Sandbox Code Playgroud)

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

//change the instance by using the sub class
_name.postValue(...)
//or _name.setValue(...)
Run Code Online (Sandbox Code Playgroud)

一般来说,这种形式的继承(增加某些方法的可见性是唯一的变化)是一种众所周知的做法吗?它在哪些场景中可能有用(假设我们可以访问所有代码)?

是的,这是众所周知的,并且上面描述的是一种常见的情况。删除观察者模式,并将其设置为 set/get 形式,同样可以从中受益。根据 ofc 在哪里实施,最终没有黄金法则。