目录
- 前言
- 一、LiveData
- 二、使用案例
- 三、LiveData 实现原理
- 四、LiveData 相关源码
- 五、LiveData分发问题
Android Jetpack之ViewModel、LiveData
Android Jetpack之LifeCycle
Android Jetpack之DataBinding+ViewModel+LiveData+Room
前言
Jetpack是一个由多个技术库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种Android版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。
一、LiveData
LiveData 是一种持有可被观察的数据存储类。和其他可被观察的类不同的是LiveData 可以在 Activity ,fragment 或者 service 生命周期发生改变时通知更新。LiveData 已经是必不可少的一环了,例如 MVVM 以及 MVI 开发模式中,都用到了 LiveData。
(注意⚠️源码是Java代码)
LIveData 的优势:
- 确保界面符合数据状态:数据发生变化时,就会通知观察者。我们可以再观察者回调中更新界面,这样就无需在数据改变后手动更新界面了。
- 没有内存泄漏,因为关联了生命周期,页面销毁后会进行自我清理。
- 不会因为Activity 停止而导致崩溃,页面处于非活跃状态时,他不会接收到任何 LiveData 事件。
- 共享资源,可以使用单例模式扩展 LiveData 对象,以便在应用中共享他们。
- 屏幕翻转数据状态保留
- 不再需要手动处理生命周期
- 数据始终保持最新状态
二、使用案例
LiveData 是一种可用于任何数据的封装容器,通常 LiveData 存储在 ViewModel 对象中。
class JokesDetailViewModel : ViewModel() { //创建 LiveData private val _state by lazy { MutableLiveData<JokesUIState>() } val state : LiveData<JokesUIState> = _state private fun loadChildComment(page: Int, commentId: Int, parentPos: Int, curPos: Int) { viewModelScope.launch { launchHttp { jokesApi.jokesCommentListItem(commentId, page)//请求数据 }.toData { //通知观察者 _state.value = JokesUIState.LoadMoreChildComment(it.data, parentPos, curPos) } } } } //观察 LiveData viewModel.state.observe(this, Observer { //更新 UI })
三、LiveData 实现原理
- Observer:观察者接口;
- LiveData:发送已经添加观察的逻辑都在其中;
- ObserverWrapper:抽象的观察者包装类;
- LifecycleBoundleObserver:继承 ObserverWrapper;
- LifecycleEventObserver,生命周期相关回调;
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; } //注册 lifecycle,生命周期改变时会回调 owner.getLifecycle().addObserver(wrapper); }
LifecycleBoundObserver(owner, observer)
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { super(observer); mOwner = owner; } //当前状态大于或者等于 STARTED 返回 true @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); } }
- 继承 ObserverWrapper 的包装类--activeStateChanged(..)方法。
- 实现LifecycleEventObserver 接口--onStateChanged(..)方法。
ObserverWrapper.activeStateChanged()
void activeStateChanged(boolean newActive) { //如果等于之前状态 if (newActive == mActive) { return; } mActive = newActive; //活跃 +1,不活跃 -1 (下面有源码) changeActiveCounter(mActive ? 1 : -1); //如果状态变成了活跃状态,直接调用 dispatchingValue,传入当前的观察者 if (mActive) { dispatchingValue(this); //(下面有源码) } } //修改活跃数量 void changeActiveCounter(int change) { int previousActiveCount = mActiveCount;//之前活跃的数量 mActiveCount += change;//总活跃数量 if (mChangingActiveState) {//如果正在更改,退出 return; } mChangingActiveState = true;//更改中 try { while (previousActiveCount != mActiveCount) { boolean needToCallActive = previousActiveCount == 0 && mActiveCount > 0; boolean needToCallInactive = previousActiveCount > 0 && mActiveCount == 0; previousActiveCount = mActiveCount; //如果当前是第一个激活的,调用 onActive if (needToCallActive) { onActive();//当活动的观察者从0 变成 1的时候调用 //如果没有激活的为 0 ,调用 onInactive } else if (needToCallInactive) { onInactive();//活跃的观察者变成 0 时调用 } } } finally { mChangingActiveState = false; } } //分发数据 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; } //数据进行派发,通知观察者 private void considerNotify(ObserverWrapper observer) { if (!observer.mActive) { return; } //再次进行判断,如果不活跃,则会更新状态,然后退出 if (!observer.shouldBeActive()) { observer.activeStateChanged(false); return; } //观察者版本是否低于当前的版本 //初始值 mLastVersion 为 -1,mVersion 为 0 //小于等于表示没有需要更新的数据 if (observer.mLastVersion >= mVersion) { return; } //更新版本 observer.mLastVersion = mVersion; //通知观察者 observer.mObserver.onChanged((T) mData); }
梳理流程:
1、通过 observe 添加一个观察者,这个观察者会被 LifecycleBoundObserver 进行一个封装,LifecycleBoundObserver继承 ObserverWrapper,并且实现了 LifecycleEventObserver。之后就会将观察添加到 Observers 中,最后注册页面生命周期的 observer。
2、当生命周期发生变化后,就会回调到 LifecycleBoundObserve 中的 onStateChanged 方法中。如果生命周期是销毁的,就会移除观察者,如果不是就会循环更新当前状态。
3、在更新状态的时候就会判断是否为活跃状态,如果是活跃状态就会进行分发,分发的时候如果观察者为 null ,就会遍历所有的观察者进行分发,否则就分发传入的观察者。
4、最后会再次判断活跃状态,已经判断观察者版本是否低于当前版本,如果都满足,就会更新观察者。
onActive 与 onInactive
如果观察者的生命周期处于 STARTED 或者 RESUMED 状态,LiveData 就会认为观察者处于活跃状态。
例如,下载数据需要在活跃状态下进行,或者需要实时的监听后台数据,就可以重新下面方法,并完成对应逻辑。
class StockLiveData(url: String) : LiveData<String>() { private val downloadManager = DownloadManager(url) override fun onActive() { if(!downloadManager.isStart()){ downloadManager.start() } } override fun onInactive() { downloadManager.stop() } }
当具有活跃的观察者时,就会调用 onActive 方法。
当没有任何活跃的观察者时,就会调用 onInactive 方法。
当然这只是我想到的场景,开发中可以根据不同的业务场景做出不同的判断。
四、LiveData 相关源码
MutableLiveData
由于 LiveData 的发送数据方法是 protected 修饰私有受保护的,所以不能直接调用。因此使用MutableLiveData 继承 LiveData 将发送数据的方法改为了 public。
public class MutableLiveData<T> extends LiveData<T> { /** * Creates a MutableLiveData initialized with the given {@code value}. */ public MutableLiveData(T value) { super(value); } /** * Creates a MutableLiveData with no value assigned to it. */ public MutableLiveData() { super(); } @Override public void postValue(T value) { super.postValue(value); } @Override public void setValue(T value) { super.setValue(value); } }
Transformations.map()
在数据分发给观察者之前对其中存储的值进行更改,返回一个新的 LiveData,可以使用此方法。
val strLiveData = MutableLiveData<String>() val strLengthLiveData = Transformations.map(strLiveData) { it.length } strLiveData.observe(this) { Log.e("---345---> str:", "$it"); } strLengthLiveData.observe(this) { Log.e("---345---> strLength:", "$it"); } strLiveData.value = "hello word" E/---345---> str:: hello word E/---345---> strLength:: 10
Transformations.switchMap()
对上面的做了个判断,根据不同的需求返回不同的 LiveData。也可以通过 id 去判断,返回对应的 livedata 即可。
val idLiveData = MutableLiveData<Int>() val userLiveData = Transformations.switchMap(idLiveData) { id-> getUser(id) }
合并多个 LiveData
val live1 = MutableLiveData<String>() val live2 = MutableLiveData<String>() val mediator = MediatorLiveData<String>() mediator.addSource(live1) { mediator.value = it Log.e("---345---> live1", "$it"); } mediator.addSource(live2){ mediator.value = it Log.e("---345---> live2", "$it"); } mediator.observe(this, Observer { Log.e("---345---> mediator", "$it"); }) live1.value = "hello" E/---345---> mediator: hello E/---345---> live1: hello
通过 MediatorLiveData 将两个 MutableLiveData 合并到一起,这样当任何一个发生变化,MediatorLiveData 都可以感知到。
五、LiveData分发问题
数据粘性事件
例如再没有观察者的时候发送数据,此时 mVersion +1,等到真正添加了观察者后,生命周期也是活跃的,那么就会将这个数据重新分发到观察者。所以说发送数据这个操作是粘性的。
如果需要去除粘性事件,可以在添加完 observe 后去通过反射修改 mVersion 和 观察者包装类中的 mLastVersion 的值,将 mVersion 赋值给 mLastVersion 即可去掉粘性事件。
数据倒灌现象
一般情况下,LiveData 都是存放在 ViewModel 中的,当Activity重建的时候,观察者会被 remove 掉,重建后会添加一个新的观察者,添加后新的观察者版本号就是 -1,所以就会出现数据再次被接收到。
这种解决方式和上面一样,反射修改版本号就可以解决。非活跃状态的观察者转为活跃状态后,只能接收到最后一次发送的数据。一般情况下我们都需要的是最新数据,如果非要所有数据,只能重写 LiveData 了。
到此这篇关于Android Jetpack组件库LiveData源码深入探究的文章就介绍到这了,更多相关Android Jetpack LiveData内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!