Android Architecture Component源码解析之LiveData

目录

源码解析目录

前言

Android应用开发的一大问题就是架构缺失,至少我观察到的是这样的。我觉得不能苛责说这是程序员水平的问题,Android本身也有它的问题。Android诞生已经超过十年了,但是Android平台并没有给我们提供一种简单明了易用的方案,来解决代码放哪这么一个基本的问题。所以,造成的结果就是不知道放哪那就往四大组件里面堆吧,堆得太多了,那就写个Util类吧,仅此而已。
Google估计也是发现了这种问题,在2017年推出了官方架构,AAC。虽然说有些晚,但是效果还是很显著的,让Android应用开发一下子从刀耕火种的原始社会,直接来到了现代化社会。不得不说,Google一出手,就知道有没有。Google I/O 2019上公布的数据说,Google Play上的Top 1000应用中有80%采用了AAC架构。足可见AAC的受欢迎程度。

问题

数据是如何传输的是任何架构的关键环节,而AAC架构的数据传输就是依靠LiveData。LiveData可谓是为Android量身定做的数据传输方案,它不仅解决了数据如何传输的问题,又解决了Android平台生命周期复杂性的问题。LiveData“神奇”的一点就在于它是可感知生命周期的,onStart之后观察者才会被通知,onDestroy的时候观察者又会被自动移除,最大程度上避免了null指针和内存泄漏。这就是我们要在LiveData源码中寻找的答案,这一切是怎么实现的。(源码版本androidx.lifecycle:lifecycle-extensions:2.2.0-alpha01)

1. LiveData的职责

LiveData应该完成哪些职责呢?无外这几点:

  1. 添加包含LifecycleOwner的观察者
  2. 在LifecycleOwner的ON_DESTROY事件时,移除观察者
  3. LiveData的数据变化后,是否通知观察者(观察者可能未处于STARTED或者RESUMED状态)
  4. 生命周期状态变化时,是否通知观察者(可能此时生命周期来到了STARTED或者RESUMED状态,之前又积压了未通知的数据)
  5. 通知观察者,并且避免重复通知

LiveData源码的主要内容就是处理这些问题。

2. LiveData添加观察者

为LiveData添加带LifecycleOwner的观察者的方式特别简单,调用其observe方法即可:

public abstract class LiveData<T> {
    /**
     * LiveData的观察者集合,以键值对的形式被添加进去,
     * 原始观察者Observer是键,对Observer的包装类ObserverWrapper是值。
     * SafeIterableMap是支持库内部实现的一种数据结构,底部以链表实现,表面上看上去却像个Map
     */
    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
            new SafeIterableMap<>();
            
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        //如果Lifecycle已经处于DESTROYED状态,直接返回
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        //对我们提供的observer进行包装,看包装类的名字 LifecycleBoundObserver 就知道,
        // 要包装成一个跟生命周期关联的观察者类
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        
        //mObservers是LiveData观察者的集合
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        //不允许相同的owner,observer组合重复添加
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        //我们的包装类LifecycleBoundObserver还是LifecycleEventObserver
        //它也被添加到了Lifecycle的观察者中
        owner.getLifecycle().addObserver(wrapper);
    }
}

//LiveData观察者的定义
public interface Observer<T> {
    void onChanged(T t);
}

代码不多,包含的东西不少。我们提供的观察者observer,在被包装之后,既被添加到了LiveData的观察者集合中,又被添加到了了Lifecycle的观察者集合中。这至少保证了两件事:第一,LiveData的数据变化后,observer可以收到通知;第二,生命周期状态变化时,observer可以收到通知。即LiveData职责的第3、第4两点。
LiveData本身定义的观察者Observer是很简单的,只有一个onChanged方法,在LiveData数据发生变化时被调用。但是,如前所述,LiveData最大的特点就是,它与生命周期的紧密关联。其observe方法包含两个参数,LifecycleOwnerObserver,每个Observer还附带了一个生命周期的拥有者LifecycleOwner。为了完成前面说的职责3和职责4,需要对Observer进行包装,以为其增加更多状态,所以才有了ObserverWrapper,LifecycleBoundObserver

public abstract class LiveData<T> {
    static final int START_VERSION = -1;
    
    //有多少LiveData的观察者处于“活动”状态
    int mActiveCount = 0;
    
    private abstract class ObserverWrapper {
        //被包装者,即LiveData原始的观察者
        final Observer<? super T> mObserver;
        //观察者是否处于“活动”状态;为原始观察者mObserver增加属性,这也是包装类的意义
        boolean mActive;
        //每个ObserverWrapper初始时version都被设置为了START_VERSION
        int mLastVersion = START_VERSION;

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

        abstract boolean shouldBeActive();

        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }

        void detachObserver() {
        }

        /**
         * ObserverWrapper的主要职责就是:接收来自外部的activeState状态的变化,
         * 这里的activeState指的是被包装者 mObserver 是否处于“活动”状态
         * 处于“活动”状态的观察者可以接收LiveData数据的变化,否则则不能;
         * 以上所说的活动状态指的是当前观察者的活动状态,可以理解为 mObserver 的活动状态,
         * LiveData本身也有活动状态,当LiveData从“活动”状态变为“非活动”状态时,其onActive方法会被调用;
         * 当LiveData从“非活动”状态变为“活动”状态时,其onInactive方法会被调用;
         * LiveData的活动状态取决于它本身的观察者是否至少有一个处于“活动”状态
         */
        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            //为LiveData处于活动的观察者计数
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive(); //LiveData中的方法,空实现
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive(); //LiveData中的方法,空实现
            }
            if (mActive) {
                //LiveData中的方法,每当观察者来的“活动”状态时,就会分发LiveData中的数据,
                //至于observer中的onChanged方法会不会被调用,还有别的判断,之后再看
                dispatchingValue(this);
            }
        }
    }
}

ObserverWrapper的主要职责是处理活动状态的变化,这种活动状态包括观察者的活动状态,和LiveData的活动状态(注意区分两者)。

在本文中,活动状态指的是一种状态,有两种情况,“活动”和“非活动”;“活动”状态指的是前述状态处于“活动”这种情况

需要注意,activeStateChanged方法是在外部被调用的,也就是说,有地方监听状态的变化,并负责通知ObserverWrapper,我们之后会看到。

再来看看对ObserverWrapper进一步的包装LifecycleBoundObserver:

public abstract class LiveData<T> {

    /**
     * 很重要的一点LifecycleBoundObserver实现了LifecycleEventObserver接口,
     * 这个接口是对于生命周期事件的观察者,详见Lifcycle源码解析
     */
    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

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

        //生命周期至少处于STARTED状态时,观察者才是“活动”状态
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        //该方法是接口LifecycleEventObserver中的方法
        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            //生命周期来到了DESTROYED,则从LiveData中移除原始的观察者mObserver
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                //指的是LiveData中的removeObserver方法
                //removeObserver方法会把观察者从LiveData的观察者集合中移除,
                //然后还会调用下面的detachObserver方法,从Lifecycle中移除观察者
                removeObserver(mObserver);
                return;
            }
            //上面提到的ObserverWrapper中的activeStateChanged方法,
            //每当生命周期变化时就调用activeStateChanged
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        //从生命周期观察者中移除
        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }
}

先来回顾一下子为LiveData添加一个观察者的流程,我们的观察者Observer被包装成了LifecycleBoundObserver,然后分别被添加到了LiveData的观察者集合中,和Lifecycle的观察者中。LifecycleBoundObserver背后其实是两层包装,第一层包装是ObserverWrapper(可以被添加到LiveData的观察者中),第二层包装是LifecycleBoundObserver(实现了LifecycleEventObserver,可以被添加到Lifecycle的观察者中)。

4803763-58eff5e323795537.png

然后再来看LifecycleBoundObserver的源码,注释中已经写得很清楚了,主要就时两点:

  1. 生命周期变化时通知活动状态是否处于“活动”中(处于“活动”状态的观察者,并且之前有“积压”的数据未通知时,观察者的onChanged方法会被调用)
  2. 生命周期来到DESTROYED时,移除相应观察者(从LiveData和Lifecycle中)

总结一下,LiveData添加观察者的内容:

  1. 对Observer进行包装
  2. 将包装后的Observer分别添加到LiveData和Lifecycle的观察者中
  3. 将生命周期的变化转换为活动状态的变化,并且通知观察者(ObserverWrapper)活动状态的变化
  4. 生命周期来到DESTROYED时,移除相应观察者(从LiveData和Lifecycle中)

LiveData职责的1、2、4条都得到了验证。下面主要来看LiveData是如何通知观察者数据改变的,并且如何避免重复的通知。也即,LiveData职责的第3、第5两条。

3. LiveData数据的通知

LiveData需要在两种情况下分发数据:

  1. LiveData本身数据发生变化时
  2. 某个观察者由于生命周期的变化而变成“活动”状态时

之所以讲分发数据,而不是通知数据的变化,是因为真正的通知数据的变化还取决于其他因素,例如,观察者是否处于“活动”状态,观察者是否已经接收过本次的数据。

改变LiveData的数据需要使用其setValue或者postValue方法,取决于是否在主线程修改数据:

public abstract class LiveData<T> {
    //数据锁
    final Object mDataLock = new Object();
    static final int START_VERSION = -1;
    //初始时下LiveData处于未设置状态
    static final Object NOT_SET = new Object();

    //LiveData真正的Data,LiveData的数据
    private volatile Object mData;
    //通过postValue设置数据
    volatile Object mPendingData = NOT_SET;
    //LiveData的数据version,用于与观察者的version进行比较,避免重复通知
    private int mVersion;

    private boolean mDispatchingValue;
    private boolean mDispatchInvalidated;
    
    private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);
        }
    };

    /**
     * 使用给定value对LiveData初始化
     */
    public LiveData(T value) {
        mData = value;
        mVersion = START_VERSION + 1;
    }

    /**
     * 默认初始化
     */
    public LiveData() {
        mData = NOT_SET;
        mVersion = START_VERSION;
    }
    
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        //切换到主线程去设置数据,ArchTaskExecutor是AAC中使用的线程池,Room也在使用
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        //version增加
        mVersion++;
        mData = value;
        //分发数据的变化
        dispatchingValue(null);
    }
}

可以看出postValue方法最终还是调用的setValue方法,setValue方法也很简单,增加版本号,设置数据,并且分发数据。
我们来跟进一下dispatchingValue方法:

public abstract class LiveData<T> {
    //initiator如果为null,证明是LiveData的数据发生了变化,要对所有观察者分发数据,
    //如果initiator不为null,那说明是因为这个initiator代表的观察者变为“活动”状态,只需要通知这个initiator本身就可以了
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        //mDispatchingValue和mDispatchInvalidated两个标志是为了防止在数据分发的时候,LiveData的数据再次发生变化;
        //例如,某个观察者onChanged方法内部又调用了setValue方法
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator); //只通知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;
    }
    
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) { //非“活动”状态的observer不通知数据的变化
            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;
        }
        //观察者的version不小于LiveData的version,说明该观察者已经被通知过了,不再通知
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //终于看到了我们observer的onChanged方法被调用
        observer.mObserver.onChanged((T) mData);
    }
}

LiveData数据分发的脉络还是很清晰的,因为LiveData数据发生变化的,对所有观察者考虑是否通知数据的变化;因为某个观察者变为“活动”状态的,只对该观察者本身考虑是否通知数据的变化。并且通过比较LiveData和观察者(ObserverWrapper)的版本号,来避免重复的通知。LiveData职责的第3、第5两条也得到了验证。


到这里,关于LiveData的源码基本上是分析完了,其中省略了如下一些内容:

  1. LiveData移除观察者
  2. 为LiveData添加“永久”的观察者(observeForever方法),说是“永久”的观察者,其实就是没有绑定生命周期的观察者,也可以手动移除。
  3. MutableLiveData

这些内容比较简单,在此略过。

4. LiveData的转换Transformations

上文提到了LiveData的onActiveonInactive方法,分别在LiveData变为“活动”和变为“非活动”时被调用,但是在LiveData本身的实现中,onActiveonInactive均为空实现。其实,单对于观察LiveData数据的变化而言,确实没有必要实现LiveData本身的活动状态的变化,这两个方法主要是用来自定义LiveData或者对LiveData进行转换的。具体使用场景见Google文档。下面具体分析一下LiveData的转换。

最简单的LiveData的转换的例子就是map,就像RxJava中的map那样。LiveData实现转换的关键是MediatorLiveData类:

//类如其名,中介者LiveData
public class MediatorLiveData<T> extends MutableLiveData<T> {
    private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();

    /**
     * 添加作为“源”的LiveData,和对“源”的LiveData的观察者
     * 当“源”LiveData数据变化,并且当前MediatorLiveData处于“活动”状态(拥有“活动”观察者)时,onChanged就会被调用
     * 实际上正如类名一样,这实际上起到了中介者的作用,MediatorLiveData传递了“源”LiveData的数据变化,同时我们又可以在onChanged中对“源”LiveData的数据进行转换
     */
    @MainThread
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        Source<S> e = new Source<>(source, onChanged);
        Source<?> existing = mSources.putIfAbsent(source, e);
        if (existing != null && existing.mObserver != onChanged) {
            throw new IllegalArgumentException(
                    "This source was already added with the different observer");
        }
        if (existing != null) {
            return;
        }
        if (hasActiveObservers()) {
            e.plug();
        }
    }

    /**
     * 移除“源”LiveData
     */
    @MainThread
    public <S> void removeSource(@NonNull LiveData<S> toRemote) {
        Source<?> source = mSources.remove(toRemote);
        if (source != null) {
            source.unplug();
        }
    }

    @CallSuper
    @Override
    protected void onActive() {
        for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
            source.getValue().plug();
        }
    }

    @CallSuper
    @Override
    protected void onInactive() {
        for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {
            source.getValue().unplug();
        }
    }

    private static class Source<V> implements Observer<V> {
        final LiveData<V> mLiveData;
        final Observer<? super V> mObserver;
        int mVersion = START_VERSION;

        Source(LiveData<V> liveData, final Observer<? super V> observer) {
            mLiveData = liveData;
            mObserver = observer;
        }

        void plug() {
            mLiveData.observeForever(this);
        }

        void unplug() {
            mLiveData.removeObserver(this);
        }

        @Override
        public void onChanged(@Nullable V v) {
            if (mVersion != mLiveData.getVersion()) {
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);
            }
        }
    }
}

单看MediatorLiveData可能比较懵逼,没事,结合map等转换一起看就明白什么意思了。

@SuppressWarnings("WeakerAccess")
public class Transformations {

    private Transformations() {
    }

    /**
     * 最简单明了的转换操作
     * 传入source “源”LiveData,将其转换为另一种类型的LiveData
     * LiveData<X> -> LiveData<Y>
     */
    @MainThread
    @NonNull
    public static <X, Y> LiveData<Y> map(
            @NonNull LiveData<X> source,
            @NonNull final Function<X, Y> mapFunction) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(source, new Observer<X>() {
            @Override
            public void onChanged(@Nullable X x) {
                //source的变化会通知到这个方法,我们用mapFunction对我们接收到的数据进行转换
                result.setValue(mapFunction.apply(x));
            }
        });
        //返回中介 MediatorLiveData
        return result;
    }

    /**
     * 这个方法比较不好理解,可以去看源码中的注释帮助理解
     */
    @MainThread
    @NonNull
    public static <X, Y> LiveData<Y> switchMap(
            @NonNull LiveData<X> source,
            @NonNull final Function<X, LiveData<Y>> switchMapFunction) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(source, new Observer<X>() {
            LiveData<Y> mSource;

            @Override
            public void onChanged(@Nullable X x) {
                LiveData<Y> newLiveData = switchMapFunction.apply(x);
                if (mSource == newLiveData) {
                    return;
                }
                if (mSource != null) {
                    result.removeSource(mSource);
                }
                mSource = newLiveData;
                if (mSource != null) {
                    result.addSource(mSource, new Observer<Y>() {
                        @Override
                        public void onChanged(@Nullable Y y) {
                            result.setValue(y);
                        }
                    });
                }
            }
        });
        return result;
    }

    /**
     * 直到source数据跟上次的数据不同时才通知
     */
    @MainThread
    @NonNull
    public static <X> LiveData<X> distinctUntilChanged(@NonNull LiveData<X> source) {
        final MediatorLiveData<X> outputLiveData = new MediatorLiveData<>();
        outputLiveData.addSource(source, new Observer<X>() {

            boolean mFirstTime = true;

            @Override
            public void onChanged(X currentValue) {
                final X previousValue = outputLiveData.getValue();
                if (mFirstTime
                        || (previousValue == null && currentValue != null)
                        || (previousValue != null && !previousValue.equals(currentValue))) {
                    mFirstTime = false;
                    outputLiveData.setValue(currentValue);
                }
            }
        });
        return outputLiveData;
    }
}

最初的Transformations类只有map这一个方法,现在又增加了两个,源码也不难理解,核心思想都是拿到“源”LiveData的数据,然后对数据做转换后,再设置给MediatorLiveData,这样通过MediatorLiveData,转换就完成了。
可以看出,LiveData是想模仿RxJava那样的操作符的,但是,LiveData的设计思想跟RxJava差别还是很大的,能实现的操作符非常有限。Transformations的主要作用是,正确传递“源”LiveData的数据变化,并且保证观察者的生命周期变化能传递给“源”LiveData。说白了,就是让MediatorLiveData没有存在感。

5. 隐藏技能

  1. 如果我们的观察者处于“非活动”状态,他变为“活动”状态后只会收到最新的数据,也就是说LiveData的数据是会“折叠”的。
  2. 除非你人为的去设置LiveData的数据为null(setValue(null)或者postValue(null)),否则在Observer的onChanged方法中接收到的数据是不可能为null的。如果使用第三方库提供的某些LiveData,在onChanged中判空是有必要的,说不定它用null代表什么特殊的含义。

6. 总结

我们的观察者经过包装后,被添加进LiveData的观察者集合,同时,也被添加到了我们提供的Lifecycle的观察者集合中(如果我们提供了LifecycleOwner的话),这样,无论是LiveData本身的数据发生变化,还是观察者变为“活动”状态时,我们的观察者都会被cue到。但是,只有当我们的观察者处于“活动”状态并且没有被通知过的时候(version低于LiveData的version),Observer的onChanged方法才会被调用。

猜你喜欢

转载自blog.csdn.net/weixin_34137799/article/details/90789082