介绍
LiveData是可观察的数据存储类,且具有生命周期感知,能实现只更新活跃的观察者(如 Activity、Fragment onResume 等活跃生命周期状态)
理解:
数据存储类,可理解为对原数据的包装,持有原数据
可观察的,LiveData可以被Observer(观察者)观察,数据更新时通知Observer(活跃状态)
活跃状态,更新时只通知活跃状态的观察者,节省资源,也无需担心因生命周期结束后继续操作相关组件导致闪退(如Activity finish 后操作界面);非活跃状态的观察者可延迟更新,即从非活跃状态变为活跃状态,会收到之前最新一次的更新通知,以达到数据同步。
具有生命周期感知,就无需手动解除观察,也不会有内存泄露问题。
使用
- 创建 LiveData,指定数据类型
- 注册观察者
- LiveData 更新数据,观察者接收更新通知
private var testLiveData: MutableLiveData<String> = MutableLiveData()
创建LiveData,一般使用LiveData的实现类MutableLiveData,并指定数据类型
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
testLiveData.observe(this) {
LogUtils.e("ccc0425", "observe string = $it")
}
注册观察者,observe接收LifecycleOwner 和 Observer,LifecycleOwner 生命周期感知,数据更新时回调 Observer onChange 方法;另 observeForever 方法也可注册观察者,无需LifecycleOwner参数,但无法感知生命周期,除解除观察外,皆可接收通知,有特殊需求可使用。
testLiveData.value = "set value"
testLiveData.postValue("post value")
更新数据有setValue 和 postValue 两个方法,如在子线程,必须使用postValue
数据共享
自定义LiveData,实现单例模式,可实现数据共享
class StockLiveData private constructor(symbol: String) : LiveData<String>() {
//活跃的观察者(LifecycleOwner)数量从 0 变为 1 时调用
override fun onActive() {
LogUtils.e("ccc0425", "onActive")
}
//活跃的观察者(LifecycleOwner)数量从 1 变为 0 时调用。这不代表没有观察者了,可能是全都不活跃了。可以使用hasObservers()检查是否有观察者。
override fun onInactive() {
LogUtils.e("ccc0425", "onInactive")
}
companion object {
private var sInstance //单实例
: StockLiveData? = null
//获取单例
@MainThread
operator fun get(symbol: String): StockLiveData? {
if (sInstance == null) {
sInstance = StockLiveData(symbol)
}
return sInstance
}
}
}
可以实现onActive和onInactive方法,做相关业务处理,如开启或关闭业务数据监测。单例实现可以多个Activity或Fragment获取同一LiveData对象,实现相关数据共享。
数据修改
private var testLiveData: MutableLiveData<String> = MutableLiveData()
private var testChange = Transformations.map(testLiveData) {
return@map "$it change"
}
testChange.observe(this) {
LogUtils.e("ccc0425", "change = $it")
}
通过Transformations.map将testLiveData的数据进行修改,将修改后的数据更新通知给观察者
数据切换
private var testLiveData: MutableLiveData<String> = MutableLiveData()
private var testLiveData2: MutableLiveData<String> = MutableLiveData()
private var switchData :MutableLiveData<Boolean> = MutableLiveData()
private var switchDataMap = Transformations.switchMap(switchData,
Function<Boolean, LiveData<String>> {
if (it) {
return@Function testLiveData
}
return@Function testLiveData2
})
switchDataMap.observe(this) {
LogUtils.e("ccc0425", "switch = $it")
}
Transformations.switchMap 可根据不同条件返回不同的LiveData
多数据源
private var testMultiData = MediatorLiveData<String>()
testMultiData.addSource(testLiveData) {
LogUtils.e("ccc0425", "liveData1 = $it")
testMultiData.value = it
}
testMultiData.addSource(testLiveData2) {
LogUtils.e("ccc0425", "liveData2 = $it")
testMultiData.value = it
}
testMultiData.observe(this){
LogUtils.e("ccc0425", "testMultiData = $it")
}
任一数据源发生改变均会通知到多数据源观察者
问题
数据倒灌
前面提到非活跃状态的观察者可延迟更新,即从非活跃状态变为活跃状态,会收到之前最新一次的更新通知,以达到数据同步。先发送了数据更新通知,后注册观察者,观察者也能收到最新的更新通知,此设计可以达到在页面重建时无需网络获取也能刷新页面数据。但是在使用数据共享时,就会出现第二次进入页面时会收到前一次的数据更新,导致页面状态出错。如 ActivityA 和 ActivityB 使用同一LiveData,A为展示页面,B为创作页面,AB均接收LiveData的通知,A中用于展示内容,B中用于处理结果,当第二次进入B时,注册了观察者之后会收到第一次的LiveData通知,与预期不符。
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
//销毁状态不做处理
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
//一个observer只注册一次
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
找到 Lifecycle 的实现类 LifecycleRegistry 的 addObserver 方法
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
enforceMainThreadIfNeeded("addObserver");
State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
if (previous != null) {
return;
}
LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
if (lifecycleOwner == null) {
// it is null we should be destroyed. Fallback quickly
return;
}
boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
State targetState = calculateTargetState(observer);
mAddingObserverCounter++;
while ((statefulObserver.mState.compareTo(targetState) < 0
&& mObserverMap.contains(observer))) {
pushParentState(statefulObserver.mState);
final Event event = Event.upFrom(statefulObserver.mState);
if (event == null) {
throw new IllegalStateException("no event up from " + statefulObserver.mState);
}
statefulObserver.dispatchEvent(lifecycleOwner, event);
popParentState();
// mState / subling may have been changed recalculate
targetState = calculateTargetState(observer);
}
if (!isReentrance) {
// we do sync only on the top level.
sync();
}
mAddingObserverCounter--;
}
查看statefulObserver.dispatchEvent(lifecycleOwner, event);
方法
static class ObserverWithState {
State mState;
LifecycleEventObserver mLifecycleObserver;
ObserverWithState(LifecycleObserver observer, State initialState) {
mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
mState = initialState;
}
void dispatchEvent(LifecycleOwner owner, Event event) {
State newState = event.getTargetState();
mState = min(mState, newState);
mLifecycleObserver.onStateChanged(owner, event);
mState = newState;
}
}
@NonNull
static LifecycleEventObserver lifecycleEventObserver(Object object) {
boolean isLifecycleEventObserver = object instanceof LifecycleEventObserver;
boolean isFullLifecycleObserver = object instanceof FullLifecycleObserver;
if (isLifecycleEventObserver && isFullLifecycleObserver) {
return new FullLifecycleObserverAdapter((FullLifecycleObserver) object,
(LifecycleEventObserver) object);
}
if (isFullLifecycleObserver) {
return new FullLifecycleObserverAdapter((FullLifecycleObserver) object, null);
}
if (isLifecycleEventObserver) {
return (LifecycleEventObserver) object;
}
........
}
mLifecycleObserver 就是LiveData中调用addObserver传入的LifecycleBoundObserver对象
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
onStateChanged方法中调用了activeStateChanged方法
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
dispatchingValue(this);
}
}
找到dispatchingValue方法
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
initiator为空时,循环整个观察者Map,这里调用considerNotify
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
当observer 的 mLastVersion 小于 LiveData 的 mVersion 时,回调onChange的方法
mLastVersion的初始值是-1,mVerSion的初始值为-1或1(无参构造函数-1、带参1)且在调用setValue时+1(postValue最终也会调用setValue)。之前场景中,LiveData第一次已经调用了setValue,mVersion是1,第二次进入B时observer.mLastVersion是初始值-1,这就解释了后注册的观察者也会收到之前最新的一次更新通知。
处理
mVersion是LiveData中的私有变量可利用反射获取具体数值进行判断
创建LiveData包装类,处理是否接收注册前的更新事件
class BaseLiveData<T>: MutableLiveData<T> {
constructor(): super()
constructor(t: T): super(t)
fun observe(owner: LifecycleOwner, isSticky: Boolean, observer: Observer<in T>) {
if (isSticky) {
super.observe(owner, observer)
} else {
val mVersion = getLiveDataMVersion(this)
super.observe(owner, StickyObserver<T>(observer, mVersion, this))
}
}
fun observeForever(isSticky: Boolean, observer: Observer<in T>) {
if (isSticky) {
super.observeForever(observer)
} else {
val mVersion = getLiveDataMVersion(this)
super.observeForever(StickyObserver<T>(observer, mVersion, this))
}
}
class StickyObserver<T>(private val observer: Observer<in T>, mVersion: Int, private val liveData: LiveData<T>): Observer<T> {
var mLastVersion :Int = mVersion
override fun onChanged(t: T) {
val newVersion = getLiveDataMVersion(liveData)
if (mLastVersion < newVersion) {
observer.onChanged(t)
}
mLastVersion = newVersion
}
}
}
fun <T> getLiveDataMVersion(liveData: LiveData<T>): Int {
val clazz = LiveData::class.java
val field = clazz.getDeclaredField("mVersion")
field.isAccessible = true
val mVersion = field.getInt(liveData)
return mVersion
}
BaseLiveData 继承 MutableLiveData,实现 observe 和 observeForever 方法(不是重写 需要新增参数)
以 observe 为例,如果 isSticky 为 true ,不做修改,若为 false ,StickyObserver 作为 super.observe 的参数,StickyObserver 继承自 Observer ,mLastVersion 初始值设置为 LiveData 中 mVersion 的值,实现 onChanged ,方法中判断 mLastVersion 和当前 mVersion 的大小从而判断是否回调观察者的 onChanged 方法,并更新 mLastVersion 的值
Demo测试
testLiveData()
testStickyLiveData.observe(this, false) {
LogUtils.e("ccc0602", "test it = $it")
}
Handler().postDelayed({
testLiveData()
}, 5000)
2021-06-02 15:59:50.118 10889-10889/com.cc.kotlin_base_mvvm E/ccc0602: testStickyLiveData set data
2021-06-02 15:59:50.118 10889-10889/com.cc.kotlin_base_mvvm E/ccc0602: do observe
2021-06-02 15:59:55.120 10889-10889/com.cc.kotlin_base_mvvm E/ccc0602: testStickyLiveData set data
2021-06-02 15:59:55.121 10889-10889/com.cc.kotlin_base_mvvm E/ccc0602: test it = sticky
观察者注册前后分别更新了数据,观察者只接收到了注册之后的更新
将 isSticky 改为 true,结果如下
2021-06-02 16:00:26.687 11149-11149/com.cc.kotlin_base_mvvm E/ccc0602: testStickyLiveData set data
2021-06-02 16:00:26.687 11149-11149/com.cc.kotlin_base_mvvm E/ccc0602: do observe
2021-06-02 16:00:26.712 11149-11149/com.cc.kotlin_base_mvvm E/ccc0602: test it = sticky
2021-06-02 16:00:31.689 11149-11149/com.cc.kotlin_base_mvvm E/ccc0602: testStickyLiveData set data
2021-06-02 16:00:31.690 11149-11149/com.cc.kotlin_base_mvvm E/ccc0602: test it = sticky
与Kotlin协程使用
官方文档示例:
使用 LiveData 时,您可能需要异步计算值。例如,您可能需要检索用户的偏好设置并将其传送给界面。在这些情况下,您可以使用 liveData 构建器函数调用 suspend 函数,并将结果作为 LiveData 对象传送。
在以下示例中,loadUser() 是在其他位置声明的暂停函数。使用 liveData 构建器函数异步调用 loadUser(),然后使用 emit() 发出结果:
val user: LiveData<User> = liveData {
val data = database.loadUser() // loadUser is a suspend function.
emit(data)
}
liveData 构建块用作协程和 LiveData 之间的结构化并发基元。当 LiveData 变为活动状态时,代码块开始执行;当 LiveData 变为非活动状态时,代码块会在可配置的超时过后自动取消。如果代码块在完成前取消,则会在 LiveData 再次变为活动状态后重启;如果在上次运行中成功完成,则不会重启。请注意,代码块只有在自动取消的情况下才会重启。如果代码块由于任何其他原因(例如,抛出 CancellationException)而取消,则不会重启。
简单封装
fun <T> BaseViewModel.requestEmit(block: EmitBlock<T>, tag: String? = "", isShowDialog: Boolean = false, loadingMessage: String = "请求网络中..."): LiveData<T> = liveData {
try {
if (isShowDialog) mStateLiveData.value = ResultState.onAppLoading(loadingMessage)
block().apply {
when {
isSuccess() -> {
mStateLiveData.value = ResultState.onAppSuccess(getResponseData() as Any)
emit(getResponseData())
}
else -> {
//业务返回 失败
val ex = AppException(getResponseCode(), getResponseMsg(), appData = if (getResponseData() == null) "" else getResponseData().toString(), tag = tag)
if (getResponseCode() == Constants.TOKEN_ERROR_CODE) {
EventHelper.getEventViewModel().tokenErrorEvent.value = Constants.TOKEN_ERROR_CODE
mStateLiveData.value = ResultState.onAppTokenError(ex)
} else {
ToastUtils.showShort(ex.errorMsg)
mStateLiveData.value = ResultState.onAppError(ex)
}
}
}
}
} catch (e: Throwable) {
paresEmitException(e)
}
}
/**
* 异常转换异常处理
*/
fun BaseViewModel.paresEmitException(e: Throwable) {
val ex = ExceptionHandle.handleException(e)
if (ex.errCode == Constants.TOKEN_ERROR_CODE) {
EventHelper.getEventViewModel().tokenErrorEvent.value = Constants.TOKEN_ERROR_CODE
mStateLiveData.value = ResultState.onAppTokenError(ex)
} else {
ToastUtils.showShort(ex.errorMsg)
mStateLiveData.value = ResultState.onAppError(ex)
}
}
使用官方推荐的 Kotlin 协程与 LiveData 的封装
mStateLiveData 的观察者error中如需判断特定请求的特定code做特殊处理,请求时需要 tag 参数用于区分请求,success 并不做业务逻辑的处理,可做 loading处理
success 业务逻辑处理 在 requestEmit 方法返回的 LiveData 的观察者中,这个观察者只有成功时才会收到更新通知
个人觉得还是使用 BaseViewModel.request 的封装,每个请求都单独处理
PS: BaseViewModel.request 之前的 kotlin 中有提及(以前的封装方式,传入 LiveData,并观察这个 LiveData 的更新)