推荐链接:
Android Jetpack之ViewModel、LiveData
Android Jetpack之DataBinding+ViewModel+LiveData+Room
Jetpack
是一个由多个技术库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种Android版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。
LiveData 已经是必不可少的一环了,例如 MVVM 以及 MVI 开发模式中都用到。
LiveData
LiveData 是一种持有可被观察的数据存储类,通常存储在 ViewModel 对象中。可以在 Activity ,fragment 或者 service 生命周期发生改变时、数据发生变化时通知UI更新。
特点
- 数据发生变化时,就会通知观察者;
- 没有内存泄漏,关联了页面生命周期,销毁后会进行自我清理;
- 屏幕翻转数据状态保留;
- 不再需要手动处理生命周期;
- 数据始终保持最新状态;
代码示例
class detailViewModel : ViewModel() {
private val _state by lazy {
MutableLiveData<T>()
}
val state : LiveData<T> = _state
private fun loadImage(page: Int) {
viewModelScope.launch {
val result = testApi.getImage("url")
_state.value = result
}
}
}
//添加观察者
viewModel.state.observe(this, Observer { //UI })
注意:当具有活跃的观察者时,就会调用 onActive 方法。当没有任何活跃的观察者时,就会调用 onInactive 方法。
LiveData 实现原理
观察者入口observe(this,Observer{})
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return; //如果已经销毁,直接退出
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) { //...添加}
if (existing != null) {
return; //添加过返回
}
owner.getLifecycle().addObserver(wrapper); //注册lifecycle
}
更新状态:根据活跃状态mActive变量boolean的值,活跃+1或不活跃-1。
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;//如果等于之前状态
}
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);//活跃 +1,不活跃 -1
if (mActive) { //如果状态变成了活跃状态,传入当前的观察者
dispatchingValue(this);
}
}
数据进行派发,通知观察者。观察者会判断版本是否低于当前的版本决定是否回调。
初始值 mLastVersion 默认为 -1,mVersion 默认为 0。
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) { return;}
if (!observer.shouldBeActive()) { //判断,如果不活跃,则会更新状态,然后退出
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) { //小于等于表示没有需要更新的数据
return;
}
observer.mLastVersion = mVersion;//更新版本
observer.mObserver.onChanged((T) mData); //通知观察者
}
梳理流程
- 通过 observe 添加一个观察者到 Observers集合。最后LifecycleOwner添加observer。
- 当生命周期发生,LifecycleBoundObserve 调用 onStateChanged 方法。如果生命周期是销毁的,就会移除观察者。否则,会While循环更新当前状态。
- 更新状态时会判断是否为生命周期是否活跃状态,如果是活跃状态就会进行分发。
- 最后判断观察者版本是否低于当前版本。
- 如果都满足,就会调用观察者onChanged方法更新UI。
LiveData缺点
数据粘性事件
例如,没有观察者的时候发送数据,此时 mVersion +1。等添加了观察者后,生命周期是活跃的,那么就会将这个数据分发到观察者。所以说发送数据这个操作是粘性的。
如果需要去除粘性事件,可以在添加完 observe 后去通过反射修改 mVersion 和 观察者包装类中的 mLastVersion 的值,将 mVersion 赋值给 mLastVersion 即可去掉粘性事件。
数据倒灌现象
LiveDatat通常存放在ViewModel中的,当Activity重建的时候,观察者会被 remove 掉。重建后会添加一个新的观察者,版本号mLastVersion 默认为 -1,所以就会出现数据再次被接收到。
这种解决方式和上面一样,反射修改版本号就可以解决。
非活跃状态的观察者转为活跃状态后,只能接收到最后一次发送的数据。一般情况下我们都需要的是最新数据,如果非要所有数据,只能重写 LiveData 了。