看起来 MutableLiveData
与 LiveData
的区别仅在于将 setValue()
和 postValue()
方法公开,而在 LiveData
中它们是受保护的。
为什么要为此更改创建一个单独的类,而不是在 LiveData
中直接定义这些方法为公共方法呢?
一般来说,这种继承形式(仅增加某些方法的可见性)是一个众所周知的实践吗?有哪些情景可以使其变得有用(假设我们可以访问所有代码)?
看起来 MutableLiveData
与 LiveData
的区别仅在于将 setValue()
和 postValue()
方法公开,而在 LiveData
中它们是受保护的。
为什么要为此更改创建一个单独的类,而不是在 LiveData
中直接定义这些方法为公共方法呢?
一般来说,这种继承形式(仅增加某些方法的可见性)是一个众所周知的实践吗?有哪些情景可以使其变得有用(假设我们可以访问所有代码)?
LiveData
,setValue()
和postValue()
方法不是公共的。而在MutableLiveData - Android Developer Documentation中,您可以看到MutableLiveData
在内部扩展了LiveData
,并且LiveData
的两个重要方法公开使用。它们是setValue()
和postValue()
。
setValue()
:设置值并将其分派给所有活动观察者,必须从主线程调用。
postValue()
:将任务发布到主线程以覆盖setValue()
设置的值,必须从后台线程调用。LiveData
是不可变的。 MutableLiveData
是LiveData
,它是可变的和线程安全的。以下是完整的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);
}
}
是的,唯一的区别在于使postValue
和setValue
公开。
我可以想到的一个用例是在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
是什么? - IgorGanapolskyMutableLiveData 是 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(...)
引言 一般而言,这种继承形式(只增加某些方法的可见性)是一种众所周知的实践,有哪些场景可以使用它呢(假设我们可以访问所有代码)?
是的,这很常见,上述描述是一个常见的场景。移除观察者模式,仅以设置/获取的形式来实现同样可以从中受益。当然,最后取决于你在哪里实现它,没有硬性规定。
LiveData
是不可变的,因为客户端无法更改其内部状态,因此具有线程安全性。 - Blackbelt