在第一行代码第三版LiveData最后一块中读到的处理数据封装的方法,之前读过一遍没搞懂,现在思路清晰了,感觉能理解了,以下是个人见解
首先,这段代码
val counter: LiveData<Int>
get() = _counter
是看懂这一整个代码的第一个关键,书中没有提到kotlin中getter和setter的概念,因为kotlin为变量提供了默认实现,而如果需要覆盖掉原来的getter,那么就需要进行手动实现,也就是在变量下方写上get() = ...
,请注意,setter是不能被覆盖的,因为val类型的数据是不能设置的,具体的kotlin语法移步官网
其次因为
MutableLiveData是一个LiveData which publicly exposes setValue(T) and postValue(T) method.
(MutableLiveData是一个公开 setValue(T) 和 postValue(T) 方法的LiveData。)
从源码中我们也可以看出
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
这两个方法的修饰符是public,也就是对外公开。
而LiveData中的方法修饰符是protected,是不能直接调用的
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
而MutableLiveData<Int>又是继承于LiveData<Int>的,所以从LiveData<Int>这个类型get一个MutableLiveData<Int>类型的变量是完全可行的。
所以这样我们给外部提供的是一个LiveData<Int>的子类MutableLiveData<Int>,但是外面外部在调用时,获得的类型实际上是LiveData<Int>,这其实就是一个多态的实现,外部获得的counter只能调用父类LiveData的方法,而不能调用子类MutableLiveData的方法(父类引用指向子类)
从而实现ViewModel的数据封装。
总结一下,一方面归结于val这个不可变变量,没有setter,另一方面就是LiveData<T>这个类中是不能直接调用setValue和postValue这两个方法的。前者是从变量类型阻断修改,后者是从LiveData本身的特性上阻断修改,两者结合,从而保证了ViewModel的数据封装。
改变前的代码:
class MainViewModel(countReserved: Int): ViewModel() {
val counter = MutableLiveData<Int>()
init {
counter.value = countReserved
}
fun plusOne(){
val count = counter.value?:0
counter.value = count+1;
}
fun clear(){
counter.value = 0
}
}
改变后的代码
class MainViewModel(countReserved: Int): ViewModel() {
val counter: LiveData<Int>
get() = _counter
private val _counter = MutableLiveData<Int>()
init {
_counter.value = countReserved
}
fun plusOne(){
val count = counter.value?:0
_counter.value = count+1;
}
fun clear(){
_counter.value = 0
}
}