/ 今日科技快讯 /
近日,根据纽约时报实时疫情地图,美国共有28个州报告了确诊病例。其中华盛顿州、加州疫情最为严重,因此诸如微软、苹果等西海岸科技巨头也备受冲击。苹果公司建议总部所有1.2万名员工在家办公。
/ 作者简介 /
本篇文章来自七零八落问号的投稿,分享了LiveData的使用以及相关的源码分析,是之前《深入AAC架构,彻底理解ViewModel的用法》这篇文章的姊妹篇,相信会对大家有所帮助!同时也感谢作者贡献的精彩文章。
七零八落问号的博客地址:
https://www.jianshu.com/p/4a65ee05e6a1
/ LiveData的主要工作 /
一个带有生命周期侦测特性的数据持有者。
AAC架构中的实际数据持有者,通常存放在ViewModel中,通过ViewModel脱离生命周期对数据的影响。
本身机制是观察者模式,在数据更新时,会通知所有已激活 (或根据需求通知未激活) 的观察者最新数据。
由于生命周期侦测的特性,LiveData在添加观察者时,要求观察者附带其生命周期所在的LifecycleOwner。
官方链接:
https://developer.android.google.cn/topic/libraries/architecture/livedata
/ LiveData的主要类 /
LiveData
核心功能类,抽象类。LiveData模块的主体,模块的基本实现都在该类中。
MutableLiveData
核心功能类。是LiveData的非抽象子类,只是把postValue()和setValue()的访问权限扩大成public并可实例化。
Observer
核心功能类,观察者接口。
LiveData$ObserverWrapper
LiveData的内部类,观察者实例的容器类的抽象父类。注册到LiveData的观察者,被会ObserverWrapper的子类包装,再加入观察者列表。
维护了对应观察者的:
当前数据版本
当前观察者的激活状态
同时负责通知LiveData的onActive()和onInactive()。
LiveData$AlwaysActiveObserver
ObserverWrapper的一个子类。通过LiveData.observeForever()传入的观察者将会被此类包装。被该类包装的观察者不关注生命周期,不受生命周期影响,并且激活状态永久为true。使用该方法时应该注意手动释放观察者,以避免内存泄漏。
LiveData$LifecycleBoundObserver
核心功能类,ObserverWrapper的一个子类。通过LiveData.observe()传入的观察者将会被此类包装。该类是LiveData生命周期监管的核心,该类实现了LifecycleEventObserver接口,并在创建后注册到观察者对应的生命周期内,以实现激活状态管理和主动释放。
MediatorLiveData
MutableLiveData的一个子类。该类除了LiveData的功能外,允许对多个LiveData的进行观察。
简单的描述
MutableLiveData会把需要观察的LiveData和对应的Observer封装为一个Source,自身则维护着Source列表。当MutableLiveData激活时,遍历Source列表,以AlwaysActiveObserver的形式对需要观察的LiveData进行注册。而MutableLiveData失去激活时,则自动移除Source列表中所有LiveData注册。任意LiveData数据更新时,根据需求,决定是否对自身进行维护或更新,即实现了对任意个LiveData的数据更新事件进行管理。
Transformations
工具类,不可实例化。用于实现LiveData的数据进行一定的流处理操作,例如发布控制,类型转换等。
工具类的方法,实际上是通过MediatorLiveData对传入的LiveData进行观察,当LiveData更新数据时,数据会传入的用户定义的方法中进行控制或转换,然后选择性通过MediatorLiveData.setValue()发布处理后的数据。
工具提供了3个方法:(livedata-2.2.0)
map
使LiveData
switchMap
根据LiveData
和map对比,map的数据源直接来自LiveData
distinctUntilChanged
屏蔽LiveData
ComputableLiveData
一个未公开的类。(livedata-2.2.0)
并非LiveData的子类,而是内部维护了一个LiveData。该类内部LiveData的数据来源,并不来自数据的设置,而是来自子类实现的compute()方法的返回值。当数据更新时,调用invalidate()方法通知LiveData重新调用compute()计算数据。默认运行在一个大小为4,专用IO操作的线程池(arch_disk_io_%i)。
/ LiveData的基本使用 /
一般使用:
class VM : ViewModel() {
val dataSource = MutableLiveData()
}
fun simple(vmOwner: ViewModelStoreOwner, lcOwner: LifecycleOwner) {
val vm = ViewModelProvider(vmOwner).get(VM::class.java)
vm.dataSource.observe(lcOwner, Observer { })
}
合并观察:
class VM : ViewModel() {
val intSource = MutableLiveData()
val dataSource = MutableLiveData()
}
fun simple(vmOwner: ViewModelStoreOwner, lcOwner: LifecycleOwner) {
val vm = ViewModelProvider(vmOwner).get(VM::class.java)
mediator.addSource(vm.intSource) { mediator.value = it.toString() }
mediator.addSource(vm.dataSource) { mediator.value = it }
}
类型装换:
fun simple() {
val source: LiveData = MutableLiveData()
val transfor: LiveData = Transformations.map(source) {
it.toString()
}
}
数据源控制:
class VMCtrl : ViewModel() {
private val stateSource = MutableLiveData()
private val dataSource1 = MutableLiveData()
private val dataSource2 = MutableLiveData()
// stateSource 数据变更时会导致 outputSource 的数据源变更
// 从而使 outputSource 数据发生变更
val outputSource = Transformations.switchMap(stateSource) {
if (it > 0) {
dataSource1
} else {
dataSource2
}
}
}
重复事件屏蔽:
class VMUntilChanged : ViewModel() {
private val source = MutableLiveData()
// source 设置同一数值,无论多少次,outputSource 只会触发一次数据更新
val outputSource = Transformations.distinctUntilChanged(stateSource)
}
单次事件发射:
https://github.com/android/architecture-samples/blob/dev-todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/SingleLiveEvent.java
事件总线:
https://www.jianshu.com/p/300ab972df6c
/ LiveData关键源码分析 /
LiveData的源码并不复杂,先从构造方法进行分析:
在构造方法中就可以直接看到LiveData的两个关键成员。
mData:当前LiveData保存的数据。
mVersion:当前mData的版本,默认-1,通过设置数据的构造方法实例化时,版本为0。
static final Object NOT_SET = new Object();
static final int START_VERSION = -1;
public LiveData() {
mData = NOT_SET;
mVersion = START_VERSION;
}
public LiveData(T value) {
mData = value;
mVersion = START_VERSION + 1;
}
从LiveData.observe()作为入口分析:
mObservers
LiveData的观察者列表,可以看到实际对象是ObserverWrapper类型,即所有传入的observer都会被ObserverWrapper及其子类封装。
assertMainThread()
该处将会检测是否在主线程调用,否则抛出异常。
LifecycleBoundObserver
ObserverWrapper子类,观察者的生命周期管理在此处实现。
existing.isAttachedTo(owner)
观察者不允许绑定多个生命周期,否则抛出异常。
同一个LiveData中,观察者不能同时 持有 / 忽略 生命周期特性,两者互斥。
addObserver(wrapper)
将LifecycleBoundObserver加入对应生命周期回调以实现自动生命周期管理。
private SafeIterableMap, ObserverWrapper> mObservers = new SafeIterableMap<>();
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
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");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
在分析LifecycleBoundObserver前,先对其父类ObserverWrapper进行分析:
mObserver
在构造方法中传入的观察者实体,即用户构建的观察者。
mActive
当前观察者的激活状态,非激活状态时将不会触发观察者的回调。
mLastVersion
当前观察者对应的数据版本。
shouldBeActive()
判断观察者是否需要激活,由子类实现。
isAttachedTo()
判断观察者是否绑定了生命周期,由子类实现,默认为false。
detachObserver()
观察者从LiveData移除时,LiveData会调用观察者包装对象的该方法,以处理必要的释放操作。
activeStateChanged()
观察者的激活状态通过该方法作出改变。
private abstract class ObserverWrapper {
final Observer super T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer super T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}
}
其中activeStateChanged()在状态改变时,有如下性质:
LiveData没有任何已激活的观察者,且此观察者激活,会回调LiveData的onActive()方法。
此观察者取消激活后,LiveData没有任何已激活的观察者,会回调LiveData的onInactive()方法。
观察者激活时,会通过dispatchingValue()通知LiveData尝试派发数据到观察者。
关键方法dispatchingValue()。该方法实际上LiveData对mObservers列表遍历进行通知尝试的方法。
当指定观察者时,尝试对该观察者派发数据;当未指定具体的观察者时,将会遍历整个mObservers列表,对所有观察者派发数据。
dispatchingValue()的具体的流程:
当前正在执行派发时,标记当次派发失效,在while循环处重新派发;指定派发目标时,只对该目标进行派发;未指定派发目标时,遍历mObservers,对所有观察者进行派发,派发期间检查失效标记,失效时,跳出当次遍历,在while循环处重新派发。
mDispatchingValue:用于标记是否真正派发数据。
mDispatchInvalidated:用于标记当前派发是否失效。
considerNotify():观察者在该方法中根据条件判断是否进行派分数据。
private boolean mDispatchingValue;
private boolean mDispatchInvalidated;
void dispatchingValue(ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
实际的派发方法considerNotify()。该方法比较简单,主要是就是对观察者进行激活和版本校验。通过校验后,记录最新版本,并推送最新数据到观察者。
!observer.mActive:当观察者未激活时,不执行派发。
observer.shouldBeActive():重复检查观察者是否应该处于激活状态,检查失败则通知观察者取消激活。
observer.mLastVersion >= mVersion:对比观察者版本,仅在版本低于LiveData版本时,通知观察者更新。
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);
}
以上即可知道整个派发流程,即通过dispatchingValue()发起,considerNotify()校验,最终派发到观察者。
回头分析LifecycleBoundObserver。
前文提到,LifecycleBoundObserver在LiveData.observe()时,即绑定到观察者所指定的生命周期中,而绑定通过owner.getLifecycle().addObserver()传入自身作为对象,即LifecycleBoundObserver必然实现LifecycleObserver。
mOwner:在构造方法中要求传入生命周期对象。
shouldBeActive():当处于生命周期处于Start - Stop之间时,观察者激活。
onStateChanged():生命周期回调。非Destory状态,通过activeStateChanged(shouldBeActive())进行自我状态校验和处理。当处于Destory时,通知LiveData移除观察者,LiveData会把包装类从mObservers列表中移除,且触发其detachObserver()方法。
isAttachedTo():直接判断生命周期对象是否相同。
detachObserver():将自身从生命周期中移除,完成整个解绑过程。
class LifecycleBoundObserver
extends ObserverWrapper
implements LifecycleEventObserver {
final LifecycleOwner mOwner;
LifecycleBoundObserver(LifecycleOwner owner, Observer observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle()
.getCurrentState()
.isAtLeast(STARTED);
}
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
通过LifecycleBoundObserver,即LiveData.observe()加入的观察者,实现了生命周期侦测,完成激活状态管理和自动解绑操作。
数据更新
数据更新有2个方法,且都比较简单,这里不贴出源码。
setValue()
只能在主线程执行,非主线程调用抛出异常。mVersion+1,mData设置为传入数据,并通过dispatchingValue(null)通知所有观察者数据数据更新。
注意数据设置时,不会进行任何的对比和校验。即设置相同数据时,同样视为更新数据。
postValue()
在任意线程中调用,传入的数据会暂存为mPendingData,最终会通过在主线程中调用setValue(mPendingData)进行数据更新。
注意的是,postValue()被多次调用时,暂存数据mPendingData会被postValue()传入的数据覆盖,最终数据为最后一次的数据。而postValue()发起的主线程任务,在执行到前,只会存在一个任务。多次postValue()调用,在真正主线程执行前,共享同一次任务。而其中的暂存数据mPendingData会被覆盖为最后一次postValue()的传入值。
使用postValue()应该注意该问题,极短时间内多次postValue()设置数据,会可能导致数据更新丢失。
LiveData.observeForever()
添加忽略生命周期侦测特性的观察者。通过该方法加入的观察者不需要传入生命周期参数,即忽略生命周期侦测。所以使用该方法时需要注意,在合适的时候调用removeObserver()移除观察,避免发生内存泄漏。
通过observeForever()传入的观察者,将会被包装为AlwaysActiveObserver,该包装类的shouldBeActive()方法估计返回true,即任何数据更新都会通知到该观察者。同一个LiveData中,观察者不能同时 持有 / 忽略 生命周期特性,两者互斥。新加入的观察者,在方法的最后都会通过activeStateChanged(true)通知LiveData更新数据到观察者。
public void observeForever(Observer super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);
}
观察者移除
观察者移除有2个方法,且都比较简单,这里不贴出源码。
removeObserver(Observer observer)
该方法用于移除指定的观察者,如果绑定生命周期,则会解除绑定。
removeObservers(LifecycleOwner owner)
仅针对通过LiveData.observe()添加,绑定了生命周期的观察者,移除维护中的所有生命周期对象为传入对象的观察者。最终也是通过removeObserver()逐一移除。
推荐阅读:
奇妙的Window之旅
Handler的文章一大把,这篇写的真形象
写一篇最好懂的https讲解
欢迎关注我的公众号
学习技术或投稿
长按上图,识别图中二维码即可关注