15

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

 4 years ago
source link: https://tech.glowing.com/cn/livedataji-chu-shi-yong-fang-shi-gong-zuo-yuan-li-shang-pian/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

引入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<T>{})
  • Fragment观察LiveData,在onCreateView/onViewCreated/onActivityCreated 注册观察, livedata.observe(viewLifeCycleOwner, Observer<T>{})
  • 不可将 LiveData直接当作EventBus
  • (Tip)建立一个MutableLiveData实例时,可以 MutableLiveData<T>() ,无需要造一个无意义的初始值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<T> { ... }) 。lifecycleOwner即activity本身。在activity由于销毁时,比如configuration change,livedata会把observer移除,也就不会有memory leak。

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

此外,虽然observe方法不会重复添加同一个obsever对象,如果在onStart/onResume中使用新建了匿名observer对象的方式绑定, liveData.observe(this, Observer<T> { ... }) ,仍然会造成错误地重复绑定多个观察者。

在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<T> { ... }) 方法写在onAttach/onCreate/onCreateView/onViewCreated/onActivityCreated哪个回调中,都不可避免建立了重复的observer。使用viewLifecycleOwner,onDestroyView时,observer就会被移除掉。由于viewLifeCycleOwner必须在onCreateView之后才能获取,onCreateView/onViewCreated/onActivityCreated时调用 liveData.observe(viewLifeCycleOwner, Observer<T>{}) 即可。选三个回调中任意一个差别不大,一般写在onActivityCreated里。

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK