Jetpack探索 -- LiveData设计思路

228 阅读7分钟

LiveData的关键在于观察者的订阅关系实现:

  • LifecycleOwner:负责生命周期回调
  • Observer:负责响应事件

那么关键在于LiveData怎么将二者联系起来:答案就是包装 -- Wrapper。

LiveData的本质

本质有两点:

  1. LifecycleBoundObserver接受Lifecycle生命周期事件:通过实现LifecycleEventObserver接口接受Lifecycle状态变化事件,当发生LiveData所关心的状态变化时被动触发监听器(如果由inActive变为active则会触发dispatchingValue方法)
  2. LiveData主动分发事件:通过调用LiveData的setValue方法主动触发监听器,如果此时LifecycleBoundObserver所绑定的Lifecycle还处于active状态,则可以接受分发。

LiveData的设计思想

先抛开LiveData,现在需要我们去观察一个对象的变化,该如何设计?

  1. 首先:“对象的变化”这个动作本身需要被我们捕捉到,因此,我们不得不定义一个泛型类LiveData<T\>,该类的T value属性就是我们观察的对象;因此,我们在LiveData中提供一个setValue方法来捕捉到"对象变化"这个动作;
  2. 然后:为了对观察者提供支持,我们还要在LiveData中提供一个添加Observer的方法observe,这样,开发者才能够通过该方法来设置监听器;
  3. 最后:如何调用上述添加的观察者来相应变化?显然,就是在setValue方法中进行相应的回调,除此之外,LiveData中还支持对当前状态的过滤,只有活跃状态时才能够回调;而处于销毁状态时,需要移除观察者。

上述就是一种粗略的需求实现,接下来我们就看看LiveData是如何设计的。

// LiveData.java
private volatile Object mData;    // 要观测的对象
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();    // 所有观察者被保存起来

上面两个是LiveData中比较重要的两个属性,其中第二个属性需要注意,其很奇怪虽然名字是一个Map,但是其实内部的结构是一个双向链表;而每次调用该Map的put方法时,都会往链表的尾部进行节点插入:

// SafeIterableMap.java
public class SafeIterableMap<K, V> implements Iterable<Map.Entry<K, V>> {

    @SuppressWarnings("WeakerAccess") /* synthetic access */
    Entry<K, V> mStart;
    private Entry<K, V> mEnd;
}

static class Entry<K, V> implements Map.Entry<K, V> {
        @NonNull
        final K mKey;
        @NonNull
        final V mValue;
        Entry<K, V> mNext;
        Entry<K, V> mPrevious;
}

订阅流程

LiveData的订阅流程就是调用observe方法就行:

// MainActivity.kt
model.mLiveData.observe(this, {
            text.text = it
        })

而observe方法内部发生了什么?

// LiveData.java
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    // 如果状态已经为DESTORYED了,那么没必要添加了,直接return
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    // 封装
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // putIfAbsent如果返回null则说明是首次添加,否则返回的是最初添加的该Wrapper
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    
    // 直接return说明每个Observer只能添加一次,不可重复添加
    if (existing != null) {
            return;
    }
    // Lifecycle的addObserver,添加生命周期监听
    owner.getLifecycle().addObserver(wrapper);
}

这里产生问题,为什么需要对Observer进行封装?实际上这就来到了上面对LiveData设计思想的猜想,因为LiveDataObserver响应的行为还牵扯到Lifecycle生命周期的状态,具体是如下两个:

  • Observer的监听方法,只有在对应Lifecycle为活跃状态时才能够被回调;
  • Lifecycle为DESTORYED状态时,需要移除Observer

以上两个都需要涉及到生命周期状态,因此LiveData就不能够简单的保存Observer,而是对其进行封装,保存封装后的ObserverWrapper。同时,observe方法的最后一行,还为Lifecycle调用addObserver添加监听器。

第一层封装

ObserverWrapper是上面封装类型LifecycleBoundObserver的父类,因此可以看做是第一层封装:

// LiveData.java
private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

        ObserverWrapper(Observer<? super T> observer) {
            mObserver = observer;
        }

    	// 正是该方法作为先制条件来判断是否处于active状态,从而判断是否执行观察者回调方法
        abstract boolean shouldBeActive();

    	// 当Lifecycler状态发生改变时可能会影响到观察者的状态,该方法就是为此做处理的
        void activeStateChanged(boolean newActive) {
            // 如果状态没变,不用处理
            if (newActive == mActive) {
                return;
            }
            
            mActive = newActive;
            // 当发生active状态改变时,通知LiveData更新相应的变量
            changeActiveCounter(mActive ? 1 : -1);
            // 这里是状态由inActive变为了Active,触发主动、精准分发
            if (mActive) {
                // 如果是从inActive变成Active,那么需要把LiveData当前的Value分发给该Observer;
                // 这是主动分发的场景,只会对该Wrapper对应的Observer进行分发
                dispatchingValue(this);
            }
        }
    }

这里我们重点关心一下activeStateChanged方法,该方法是该类中唯一提供了方法实现的方法,该方法内容在注释中已经写明了。这里在重点提一句上述的dispatchingValue调用,在这里调用的时候传入了this作为方法参数,而在LiveData的其他地方回调dispatchingValue方法时,传递的都是null;这种差别就在于,传递this时,dispatchingValue方法内部只会对this代表的ObserverWrapper中的Observer进行监听回调;而传递null时,dispatchingValue会遍历LiveData的mObservers中所有的ObserverWrapper中的Observer进行监听回调。所以说,这里是一种:==主动的、精准分发==。

第二层封装

而第二层封装类为LifecycleBoundObserver,该类相较于父类最重要的是实现了LifecycleEventObserver接口,具备了接受Lifecycle生命周期回调的能力,而该类中最重要的两个方法实现就分别来自父类的shouldBeActive与LifecycleEventObserver接口的onStateChanged:

// LiveData.java
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {  // 注意,实现了LifecycleEventObserver接口
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            // 该方法根据Lifecycle状态作为判断依据
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

    	// LifecycleEventObserver接口的方法,响应Lifecycle生命周期变化事件
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            // 证明猜想:DESTORYED时移除Observer
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                // 根据上面对activeStateChanged方法的分析,当Lifecycle从CREATED变为STARTED时,
                // 会触发内部主动分发dispatchingValue调用
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

相关重要方法的内容通过注释已然明白,可以发现,相较于父类,LifecycleBoundObserver则负责与Lifecycle打交道,即负责接收Lifecycle生命周期变化,做出响应。

同时,上述onStateChanged方法实现中,已经体现了我们猜想之一的:当Lifecycle为DESTORYED时,需要移除Observer。

小结

通过上述订阅流程分析,我们可以对该过程进行小结一下:

LiveData的observe方法会先对Observer进行封装,然后将封装后的对象保存进mObservers中,而mObservers是一个双向链表;封装后的Observer就有了接受Lifecycle申明周期变化事件的能力(原因是实现了LifecycleEventObserver接口),并且,会在Lifecycle从CREATED变为STARTED(此时Observer状态变为Active)状态时触发主动、精准分发dispatchingValue;最后,为Lifecycle调用addObserver添加封装后的Observer来接收Lifecycle生命周期变化事件。

setValue

根据上面的猜想,setValue中需要做两件事:

  1. 捕捉到“对象改变”这一动作;
  2. 捕捉到动作后,进行分发,调用Observer的监听回调。

接下来就看看,LiveData是如何实现的:

// LiveData.java
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    // 注意,此时正如上文所说,这里传递的参数为null!!
    dispatchingValue(null);
}

方法很直戳了当,直接调用dispatchingValue进行分发:

// LiveData.java
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    // 该boolean变量用来限制同时只能执行一个dispatchingValue
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            // 这里对应的是参数不为null的情况,只会调用considerNotify分发给initiator一个Observer
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                // 这里使用Iterator来完成对mObservers中所有Observer的分发
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

方法也很清晰明了:这里针对参数initiator是否为null的情况不同处理很清楚,即initiator不为null的情况下,只会调用considerNotify分发一次,是一种精准的分发;而initiator为null,则会遍历mObservers中所有Observer,逐个调用considerNotify进行分发,是一种地毯式分发

// LiveData.java
private void considerNotify(ObserverWrapper observer) {
    // 如果observer不在active状态了,直接return,不必分发了
        if (!observer.mActive) {
            return;
        }
        // 证明猜想:当不为active时,不会调用Observer监听回调
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
    // 通过重重难关,调用Observer的onChanged回调!!!
        observer.mObserver.onChanged((T) mData);
    }

方法很简单,不多说了。

问题

在Android开发者中介绍LiveData时有如下内容:

即在我们上面分析时提到,首次调用observe添加Observer时,在对Observer的封装过程中,由于具备了接受Lifecycle生命周期状态改变事件的能力,会在CREATED变为STARTED时触发一次主动、精准分发dispatchingValue,那么此时如果LiveData的value为null的话,上述的nameTextView展示的文本应该为null才对,但事实是不会!!TextView展示的文本依旧是xml文档中text设置的内容。但是!!如果LiveData的value被初始化了,那么TextView展示的文本就是LiveData中的内容了!!

对于这个问题,还未弄懂。