LiveData 源码分析

何言 2021年08月11日 98次浏览

LiveDatajetpack 包里的一个组件,这个组件主要的作用是作为一个可观察数据的持有者,它维护一个变量,可以注册监听者,然后再变量修改的时候通知监听者。

LiveData 只是一个很小的工具,在 MVVM 架构中,我们一般将 LiveData 对象放到 ViewModel 里,之后有时间会学习一下 ViewModel 的使用,这里先简单介绍一下 LiveData

MutableLiveData

LiveData 是一个抽象类,我们一般使用它的的一个实现类 MutableLiveData,当然你自己实现一个实现类也是可以的,此处就以 MutableLiveData 为例子介绍。

构造

构造很简单,直接指定泛型并调用构造方法即可:

val liveData = MutableLiveData<String>()
val liveDataWithDefault = MutableLiveData<String>("default")

至此,我们就创建了一个 MutableLiveData 对象

方法

MutableLiveData 常用的有如下方法:


fun getValue():T?

fun setValue(value:T):Unit

fun postValue(value: T): Unit

fun observe(owner:LifecycleOwner, observer: Observer<T>):Unit

fun observeForever( observer: Observer<T>):Unit

fun removeObserve(observer: Observer<T>):Unit

总结

这里直接放出总结,之后是源码分析。

对于 getValue ,当 LiveData 还未指定值的时候会返回 null ,哪怕在 Kotlin 中指定泛型为非空,也会返回空。

对于 setValuepostValue ,两者都可以更新当前值并通知给观察者,前者只能运行在主线程,后者会主动切换回主线程,因此可以在任何线程调用,不过会产生并发问题(当调用 postValue 之后立即调用 getValue,值可能还没更新)。

对于 observeobserveForever ,两者都可以向 LiveData 添加观察者,前者与传入的 LifecycleOwner 有关,后者无关,只要值发送改变,就一定会接收到更新。

对于 observe 添加的观察者,具有如下特性:

  1. LifecycleOwner 当前周期为 DESTROYED 的时候,添加会失败,如果已经添加了,则会移除。
  2. LifecycleOwner 的周期为 STARTED 之后的时候,观察者才会为 Active 状态
  3. 当值发送改变的时候,只有 Active 状态的观察者会更新
  4. LifecycleOwner 第一次由 非 Active 变为 Active 的时候,只要当前值不是 NO_SET ,都会通知观察者一次
  5. LifecycleOwner 第二次由 非 Active 变为 Active 的时候,如果在上次处于 Active 之间值更新过,则会通知观察者一次

获取当前值

获取当前值,我们可以调用 getValue 方法,不过在 Kotlin 中,会被自动转换为获取 value 成员变量,因此 Kotlin 中可以直接使用 liveData.value 去获取当前值,这里注意返回值类型,在 Kotlin 中类型是安全的,但是上面可以看到当我们指定泛型为 T 的时候,返回值是 T?,也就是永远不是空安全的。我们可以查看 getValue 方法的源码看出问题:

/**
     * Returns the current value.
     * Note that calling this method on a background thread does not guarantee that the latest
     * value set will be received.
     *
     * @return the current value
     */
    @SuppressWarnings("unchecked")
    @Nullable
    public T getValue() {
        Object data = mData;
        if (data != NOT_SET) {
            return (T) data;
        }
        return null;
    }

以上是 LiveDatagetValue 的源码,因为使用的是 Java 所以返回值没有空安全检查,不过加入了 @Nullable 注解表明不是空安全的,因此如果在 Kotlin 语言中调用会返回 T?
同时我们可以看到在 Kotlin 环境中当我们指定泛型为空安全时候返回 null 只有一种情况,就是当 data == NOT_SET 的时候,通过命名也可以猜出此时应该是我们调用无参构造方法,还未传入任何值的时候。
其实从 LiveData 的作用来看,我个人是不太建议调用 getValue 方法的,具体可以看下面内容。

更新值

更新值,有两个方法 setValuepostValue ,其实按照安卓的命名规律,光看名字都能猜出个大概,我们可以直接看源码:

/**
     * Sets the value. If there are active observers, the value will be dispatched to them.
     * <p>
     * This method must be called from the main thread. If you need set a value from a background
     * thread, you can use {@link #postValue(Object)}
     *
     * @param value The new value
     */
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

我们注意到这里有 MainThread 注解,还调用了一个 assertMainThread 方法,继续来到这个方法:

static void assertMainThread(String methodName) {
        if (!ArchTaskExecutor.getInstance().isMainThread()) {
            throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
                    + " thread");
        }
    }

可以看到他会使用 ArchTaskExecutor 来检查当前是否为主线程,当不是主线程的时候会抛出异常,所以 setValue 只能在主线程调用。
此外,我们还注意到这里有一个 mVersion++ 的操作,这里涉及到一些 LiveData 的高级内容,下次有空再来讲解一波吧。
此外,Kotlin 会对 setXX 的方法进行转换,因此如果在 Kotlin 中,我们可以直接使用 liveData.value = "xx" 来调用 setValue 方法。

/**
     * Posts a task to a main thread to set the given value. So if you have a following code
     * executed in the main thread:
     * <pre class="prettyprint">
     * liveData.postValue("a");
     * liveData.setValue("b");
     * </pre>
     * The value "b" would be set at first and later the main thread would override it with
     * the value "a".
     * <p>
     * If you called this method multiple times before a main thread executed a posted task, only
     * the last value would be dispatched.
     *
     * @param value The new value
     */
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

首先是一个同步锁,锁内将 mPendingData 的值设置为 value,并且如果 mPendingDataNOT_SET 的时候就使用 ArchTaskExecutor 在主线程运行一个 Runnable ,来看看这个 Runnable

 private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        setValue((T) newValue);
    }
};

同样也是同步锁,这里将 mPendingData 恢复成 NOT_SET 并调用 setValue 方法,注意这个 Runnable 是运行在主线程中的,也就是说 postValue 可以运行在任意线程中,并且在连续多次调用的时候只有最后一次会生效,这是使用了 mPendingData 作为缓冲实现的,调用 postValue 的时候,只有当当前没有缓冲的时候才会将 Runnable 放入 ArchTaskExecutor 运行,在运行之前我们调用 postValue 的时候只会更新 mPendingData ,并不会执行 Runnable ,当 Runnable 执行中在将 mPendingData 恢复为 NOT_SET

监听数据

这里是重点,因此作为一个一级标题,首先我们看看绑定观察者的方法,有两个:

fun observe(owner:LifecycleOwner, observer: Observer<T>):Unit

fun observeForever( observer: Observer<T>):Unit

来看看源码吧:

    /**
     * Adds the given observer to the observers list within the lifespan of the given
     * owner. The events are dispatched on the main thread. If LiveData already has data
     * set, it will be delivered to the observer.
     * <p>
     * The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED}
     * or {@link Lifecycle.State#RESUMED} state (active).
     * <p>
     * If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will
     * automatically be removed.
     * <p>
     * When data changes while the {@code owner} is not active, it will not receive any updates.
     * If it becomes active again, it will receive the last available data automatically.
     * <p>
     * LiveData keeps a strong reference to the observer and the owner as long as the
     * given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to
     * the observer &amp; the owner.
     * <p>
     * If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData
     * ignores the call.
     * <p>
     * If the given owner, observer tuple is already in the list, the call is ignored.
     * If the observer is already in the list with another owner, LiveData throws an
     * {@link IllegalArgumentException}.
     *
     * @param owner    The LifecycleOwner which controls the observer
     * @param observer The observer that will receive the events
     */
    @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);
    }

注解有点长哈,内容其实不多,首先是确保在主线程调用,接下来就检查一下 LifecycleOwner 的生命周期,如果是 DESTROYED 的时候添加失败,后面就是将 observer 保存起来,同时我们看到最后在 LifecycleOwner 中添加了一个 warpper 对象,我们进入 LifecycleBoundObserver 看看:

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

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

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

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

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

比较重要的有两个方法:

@Override
boolean shouldBeActive() {
    return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

@Override
public void onStateChanged(@NonNull LifecycleOwner source,
        @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            /*省略,接下来会讲到*/
        }

shouldBeActive 后面会讲到,主要来看 onStateChanged ,这是继承的 LifecycleEventObserver 的方法,并且刚刚也看到它监听了 owner ,其实内容也不难理解,就是当 LifecycleOwner 变为 DESTROYED 的时候移除观察者,这也不难理解,就是在组件被销毁的时候自动移除观察者。

其实对于使用 observe 绑定的观察者,它的特性会与传入的 owner 绑定,主要体现为两点:

  1. ownerDESTROYED 的时候,无法添加观察则,当 owner 变为 DESTROYED 的时候移除观察者:
  2. 只有当 owner 处于某些特定生命周期的时候,观察者才会接收到数据监听,并且当 owner 从某些生命周期变为某些生命周期的时候,哪怕数据没发生更新,也会调用观察者,这点将在之后进行说明:

接下来看看 observeForever

/**
     * Adds the given observer to the observers list. This call is similar to
     * {@link LiveData#observe(LifecycleOwner, Observer)} with a LifecycleOwner, which
     * is always active. This means that the given observer will receive all events and will never
     * be automatically removed. You should manually call {@link #removeObserver(Observer)} to stop
     * observing this LiveData.
     * While LiveData has one of such observers, it will be considered
     * as active.
     * <p>
     * If the observer was already added with an owner to this LiveData, LiveData throws an
     * {@link IllegalArgumentException}.
     *
     * @param observer The observer that will receive the events
     */
    @MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        wrapper.activeStateChanged(true);
    }

可以看到内容其实差不多,不过 wrapper 对象变为了 AlwaysActiveObserver,同样来看看:

private class AlwaysActiveObserver extends ObserverWrapper {

    AlwaysActiveObserver(Observer<? super T> observer) {
        super(observer);
    }

    @Override
    boolean shouldBeActive() {
        return true;
    }
}

这个就简单多了,可以看到 shouldBeActive 永远返回 true ,同时也没有和 LifecycleOwner 绑定,事实上,通过 observeForever 绑定的观察者,只要数据发生变化就一定会通知,对于这种观察者,我们只能调用 removeObserver 来移除这种观察者。

数据监听

来看看 LiveData 是如何通知观察者的,因为 postValue 之后也是调用 setValue 方法,所以我们还是回到 setValue 方法的源码:

    /**
     * Sets the value. If there are active observers, the value will be dispatched to them.
     * <p>
     * This method must be called from the main thread. If you need set a value from a background
     * thread, you can use {@link #postValue(Object)}
     *
     * @param value The new value
     */
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

可以看到有一个 dispatchingValue 方法,我们来看看:

@SuppressWarnings("WeakerAccess") /* synthetic access */
    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;
    }

主要是这里通过迭代器遍历观察者的 map 然后来到了 considerNotify 方法:

@SuppressWarnings("unchecked")
    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);
    }

可以看到,只有 observer.shouldBeActive() 返回 true 才会通知,还记得刚刚的两种观察者吗,对于 observeForever 绑定的观察者,这里永远会是 true ,而对于 observe 绑定的观察者,可以看到:

@Override
boolean shouldBeActive() {
    return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}

只有当 LifecycleOwner 当前状态在 STARTED 之后的时候才会调用,例如在 Activity 里,只有在 onStart 之后,onStop 之前观察者才会有效。

实际上,不止这时候有效,在刚刚的 LifecycleBoundObserveronStatusChange 方法中,还做了一些特殊处理,这部分源码分析起来比较麻烦,因此我这里直接放结论了,就在之前总结之中。