android livedata原理,LiveData基础使用方式+工作原理(上篇)

引入androidx后,ViewModel+LiveData搭配Activity/Fragment渐渐成为大家喜爱(习惯)的UI制作方式。

总体来说,这套模式的容易学习,使用也方便,但如果没有详细了解其背后的工作机制,也很容易错误使用造成bug。

在此将分享相关architecture component背后原理,将实际开发中遇到的问题和错误总结一些good practice points,以供参考。

这篇文章主要探讨LiveData的工作原理

和基本使用方式

How it works:

LiveData::setValue VS LiveData::postValue

LiveData::observe(lifecycleOwner, observer)

Good Practice Points:

Activity观察LiveData,在onCreate注册观察,livedata.observe(this, Observer{})

Fragment观察LiveData,在onCreateView/onViewCreated/onActivityCreated 注册观察,livedata.observe(viewLifeCycleOwner, Observer{})

不可将

LiveData直接当作EventBus

(Tip)建立一个MutableLiveData实例时,可以MutableLiveData()

,无需要造一个无意义的初始值null/emptylist,避免观察到无意义的值。

LiveData::setValue vs LiveData::postValue

更新一个MutableLiveData实例中值,需要通过setValue或postValue方法,其中setValue只能在主线程调用。为什么有这样的设计呢?

阅读LiveData(MutableLiveData的父类)源码,其内部使用了俩个volatile修饰的成员变量,mData和mPendingData。

mData保存了最终数据。LiveData实例暴露给外部取值的getValue方法,以及其内部推送数据给观察者时,使用的都是mData。mData只能通过setValue方法更新,即只能由main thread写入,加上volatile的特性(直写main memory而非cpu cache),写入的新值将对所有线程可见。所以不会出现mData更新后,还有线程读取到更新前数据的情况。

那主线程外更新数据怎么实现呢?就由postValue利用mPendingData完成。

mPendingData中保存了将要但还未被写入mData中的值。postValue方法中,新的数据先被写入mPendingData,然后post一个runnable task到主线程。task中调用setValue方法将mPendingData中的值写入mData,接着清除mPendingData中的值。在postValue和task中,mPendingData的读写都由synchronized block包裹。即postValue中和task中对mPendingData的操作不会并行,避免了postValue对mPendingData的赋值正好被task中mPendingData清除覆盖的情况。

postValue source code

protected void postValue(T value) {

boolean postTask;

synchronized (mDataLock) {

postTask = mPendingData == NOT_SET;

mPendingData = value;

}

if (!postTask) {

return;

}

ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);

}

另外,postValue时,如果当前已有task就不会再post新的task。所以task被执行前,无论postValue被调用多少次,只有最后一次postValue中传入的值,会被更新入mData。也就是说,观察者们不会观察到之前多次postValue中的数据。

task source code

private final Runnable mPostValueRunnable = new Runnable() {

@SuppressWarnings("unchecked")

@Override

public void run() {

Object newValue;

synchronized (mDataLock) {

newValue = mPendingData;

mPendingData = NOT_SET;

}

setValue((T) newValue);

}

};

所以,LiveData不能直接

被当作事件线

使用。它的事件是会“丢失”的。它更像是Rx中的BehaviorSubject而非Observerable。除了上述原因,观察者从inActive状态切换到active状态时,会“主动”观察当前LiveData中的值,也是LiveData不可作事件线用的另一个原因。

LiveData::observe

在activity/fragment中观察LiveData,我们一般都会创建一个observer实例,调用liveData.observe(lifecycleOwner, observer)方法,在observer的回调方法onChanged中,实现UI的更新,无需再判断当前lifecycle来决定是否要更新。

observe source code

@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");

}

if (existing != null) {

return;

}

owner.getLifecycle().addObserver(wrapper);

}

liveData的成员变量mObservers保存了所有observer和它们各自的相关的lifecycleowner。

在observe方法中,observer和lifecycleOwner包裹成一个新的lifecycleBoundObserver对象,在检查有效性后,observer和包裹后的lifecycleBoundObserver分作为key、value存入mObservers中。

lifecycleBoundObserver实现了LifecycleEventObserver接口。

执行lifecycle.addObserver(lifecycleBoundObserver)后,即可在lifecycle状态(state)变化时,触发lifecycleBoundObserver.onStateChanged,根据lifecycle当前状态,决定observer是否活跃(active), 从而决定是否要接收livedata中的数据更新。

lifeBoundObserver.shouldBeActive方法,定义了lifeCycle至少处于STARTED以及之后状态,observer才是active的。

状态从inactive变成active时,lifeBoundObserver会调用liveData.dispatchingValue(this)

方法,让liveData把mData中的告知自己,从而通知其包含的observer。

例如,一个在background的activity回到foreground时,其相关的observer也从inactive变成active,也就是onStart后,马上会收到当前livedata中的值。

需要知道的是,lifeCycle不仅会在state真正改变时通知lifecycleBoundObserver。调用lifecycle.addObserver(lifecycleBoundObserver)

后,它会把达到当前状态前经历的所有LifeCycle.Event都发送给lifecycleBoundObserver。

例如,当前lifeCycle状态为RESUMED,lifecycle.addObserver(lifecycleBoundObserver)

后,

lifeBoundObserver.onStateChanged 马上连续收到ON_CREATE,ON_START,ON_RESUME三个事件。可以想象成“补收”之前的事件。在这种情况下,因为onStateChanged在收到ON_CREATE时,lifecycle已经处于RESUME状态,再STARTED之后,所以observer已是活跃的。所以比如在activity onResume后,onPause前,让一个obsever开始观察livedata,那么这个observer的onChange方法会立马被调用(如果mData已经设置过的情况)。

所以,observer并不只是再数据变化时收到“推送”,也可在lifecycle状态变化时收到通知。这也是上面提到,不能直接作为事件线使用的另一个原因。

LiveData.observe调用时机

在activity中,一般在onCreate回调中执行liveData.observe(this, Observer { ... })

。lifecycleOwner即activity本身。在activity由于销毁时,比如configuration change,livedata会把observer移除,也就不会有memory leak。

由于livedata的observer本身就会在STARTED之后开始观察,无需把绑定observer放在onStart/onResume中。

此外,虽然observe方法不会重复添加同一个obsever对象,如果在onStart/onResume中使用新建了匿名observer对象的方式绑定,liveData.observe(this, Observer { ... })

,仍然会造成错误地重复绑定多个观察者。

在fragment中,需注意lifecycleOwner应该使用viewLifecycleOwner,而不是fragment本身(Android Studio已经会提醒)。fragment的lifecycle比较复杂。有些情况下,onDestroy不会调用到,即到达不了DESTROYED状态,造成observer没有被移除,绑定重复的observer。举个例子,一个非retained fragment实例,在configuration change时,将经历onPause>onStop>onDestroyView>onDetach>onAttach>..onStart>onResume, 其lifecycle不会经历destroyed状态,不管将liveData.observe(this, Observer { ... })

方法写在onAttach/onCreate/onCreateView/onViewCreated/onActivityCreated哪个回调中,都不可避免建立了重复的observer。使用viewLifecycleOwner,onDestroyView时,observer就会被移除掉。由于viewLifeCycleOwner必须在onCreateView之后才能获取,onCreateView/onViewCreated/onActivityCreated时调用liveData.observe(viewLifeCycleOwner, Observer{})

即可。选三个回调中任意一个差别不大,一般写在onActivityCreated里。

LiveData基础的使用介绍到这里,下一篇预告:LiveData基础使用方式+工作员(下篇) MediatorLiveData & Transforms

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值