joy keeps flowin'

Jetpack系列之LiveData

xx
目次

Jetpack中最不陌生的大概就是LiveData了,LiveData的两个特点:和lifecycleOwner绑定且监听数据变化。用过的哪个不说好?

流程 #

常用的LiveData的形式大概是这样的:

1
2
3
4
5
6
7
8
val mutableLiveData = MutableLiveData<String>()
mutableLiveData.observe(this){
  // ...
}

// 更新值
mutableLiveData.postValue(...)
mutableLiveData.setValue(...)

今天写的是LiveData怎么上来就是MutableLiveData呢?

MutableLiveData是LiveData子类,LiveData还是抽象类,拿来就能用的就是MutableLiveData了。

监听时有两个方法,分别是public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)public void observeForever(@NonNull Observer<? super T> observer)

observe传入的LifecycleOwner参数用作监听生命周期变化,LifecycleOwner被销毁前移出观察者。不会因此造成npe问题。 observeForever则不在意谁是否被销毁,只要有会通知。

虽然两个方法传入的Observer是一样的类型,但在执行添加观察者时,又封装了一层,添加了版本、活跃状态及方法。observe方法添加的是LifecycleBoundObserver类型对象,observeForever添加的则是AlwaysActiveObserver类型对象,两者的基类是ObserverWrapper。

更新值从调用setValue或是postValue方法开始,postValue用于子线程中执行,通用handler的方式使得更新值的操作在主线程中执行,实际执行的还是setValue。

直接看setValue吧。setValue之后,LiveData内部做了三步,分别是:

  1. 判断主线程
  2. 更新version
  3. 保存更新后的值
  4. 通知observer

先看通知observer,方法中可以传入一个可选的ObserverWrapper类型参数,对应上面的基类,如果传入了,只分发给这一个观察者,否则分发给所有的观察者。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   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;
    }

重点的是决定观察者是否执行的方法:considerNotify。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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);
    }

有几个值得关注的点:

  1. mActive
  2. mVersion

只有状态是active时才该ObserverWrapper对象才可以通知观察者值变化了,状态的更新和获取都是和ObserverWrapper具体的实现类有关的,是哪一种类型又取决于通过哪种方式添加的观察者。

mVersion的值也需要是最新的,都很合理。

这大概就是LiveData中最主要的方法和相关流程,不知道你是否对主线程、mActive和mVersion有疑问,我是有的,为什么需要这些呢?分别来假设一下这些值没有会怎么样。

mActive #

mActive起了什么作用?需要保证观察者处于活跃状态才能接收到值的变化。如果所有观察者总是活跃状态会有什么问题吗?我相信是没有的,LifecyclerOwner总能保证按时移出。

mVersion #

mVersion又起了什么作用呢?mVersion变化来源是从setValue开始的,每更新一次value值,version就会更新一次。当观察者满足条件执行了,观察者内部的版本就会更新到最新。这样就可以理解成观察者活跃时总要保持最新的状态。

如果没有mVersion会发生什么呢?只要值变化就更新,即使是因为时序问题传过来一个过时的值。那这个值就是不能缺少的。

主线程 #

为什么所有的更新需要在主线程呢?不在主线程行不行?我相信也是可以的。大不了赋值时加锁,需要更新ui时谁需要谁切换好了。

数据倒灌??? #

问题的原因是在添加观察者时,会把最新的状态一并传过去,这时候观察者就要更新到最新的状态。网上的博客中有很多解决方式,今天不谈解决。

有没有可能Google就是这么设计的呢?如果时这么设计的,意图就是为了保证最新的状态,那么主线程执行是不是也能说的通了,版本、活跃状态是不是也能说的通了?

所以它就是不是一个问题,Google设想的场景就不是通知状态变化的,而是保证所有的观察者保持最新的状态。

组成 #

MutableLiveData的代码没有额外的实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class MutableLiveData<T> extends LiveData<T> {

    /**
     * Creates a MutableLiveData initialized with the given {@code value}.
     *
     * @param value initial 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);
    }
}

LiveData的实现除了MutableLiveData还有个MediatorLiveData,是MutableLiveData的子类。根据官方注释中的解释,作用是用来协调多个LiveData,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
 * {@link LiveData} subclass which may observe other {@code LiveData} objects and react on
 * {@code OnChanged} events from them.
 * <p>
 * This class correctly propagates its active/inactive states down to source {@code LiveData}
 * objects.
 * <p>
 * Consider the following scenario: we have 2 instances of {@code LiveData}, let's name them
 * {@code liveData1} and {@code liveData2}, and we want to merge their emissions in one object:
 * {@code liveDataMerger}. Then, {@code liveData1} and {@code liveData2} will become sources for
 * the {@code MediatorLiveData liveDataMerger} and every time {@code onChanged} callback
 * is called for either of them, we set a new value in {@code liveDataMerger}.
 *
 * <pre>
 * LiveData&lt;Integer&gt; liveData1 = ...;
 * LiveData&lt;Integer&gt; liveData2 = ...;
 *
 * MediatorLiveData&lt;Integer&gt; liveDataMerger = new MediatorLiveData&lt;&gt;();
 * liveDataMerger.addSource(liveData1, value -&gt; liveDataMerger.setValue(value));
 * liveDataMerger.addSource(liveData2, value -&gt; liveDataMerger.setValue(value));
 * </pre>
 * <p>
 * Let's consider that we only want 10 values emitted by {@code liveData1}, to be
 * merged in the {@code liveDataMerger}. Then, after 10 values, we can stop listening to {@code
 * liveData1} and remove it as a source.
 * <pre>
 * liveDataMerger.addSource(liveData1, new Observer&lt;Integer&gt;() {
 *      private int count = 1;
 *
 *      {@literal @}Override public void onChanged(@Nullable Integer s) {
 *          count++;
 *          liveDataMerger.setValue(s);
 *          if (count &gt; 10) {
 *              liveDataMerger.removeSource(liveData1);
 *          }
 *      }
 * });
 * </pre>
 *
 * @param <T> The type of data hold by this instance
 */

LiveData的独生子是MutableLiveData,MutableLiveData的独生子是MediatorLiveData。两代单传!

标签:
Categories: