你对于LiveData真的了解吗?看完原理立马释怀!

简介: / 前言 /LiveData是Jetpack的基础组件之一,在很多模块中都可以看到其身影。LiveData可以和生命周期绑定,当Lifecycle(例如Activity、Fragment等)处于活跃状态时才进行数据回调,并在Lifecycle处于无效状态(DESTROYED)时自动移除数据监听行为,从而避免常见的内存泄露和NPE问题。

/ 前言 /

LiveData是Jetpack的基础组件之一,在很多模块中都可以看到其身影。LiveData可以和生命周期绑定,当Lifecycle(例如Activity、Fragment等)处于活跃状态时才进行数据回调,并在Lifecycle处于无效状态(DESTROYED)时自动移除数据监听行为,从而避免常见的内存泄露和NPE问题。


本文就来介绍下LiveData的内部实现逻辑,从而让读者在知道其使用方法之外,还可以了解到其实现原理以及以下几点比较容易忽略的重要特性:


一个Observer对象只能和一个Lifecycle对象绑定,否则将抛出异常

同个Observer对象不能同时使用observe()和observeForever()函数,否则将抛出异常

LiveData存在丢值的可能性。当单线程连续传值或者多线程同时postValue时,最终可能只有最后一个值能够被保留并回调

LiveData 存在仅有部分 Observer 有收到值回调的可能性。当单线程连续传值或者多线程同时传值时,假设是先后传valueA和valueB,可能只有部分Observer可以接收到valueA,然后所有Observer都接收到了valueB

本文所讲的的源代码基于以下依赖库当前最新的release版本:

compileSdkVersion 29
 implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"

/ Observer /

LiveData包含两个用于添加数据观察者(Observer)的方法,分别是


observe(LifecycleOwner , Observer)

observeForever(Observer)


两个方法的区别对于外部来说只在于是否提供了生命周期安全的保障。


一、生命周期安全的observe


observe(LifecycleOwner , Observer)方法的函数签名如下所示。传入的LifecycleOwner参数意味着携带了Lifecycle对象,LiveData内部就根据 Lifecycle的生命周期事件的回调变化在合适的时机进行数据通知,并在 Lifecycle对象处于DESTROYED状态时自动移除Observer,这也是LiveData避免内存泄漏的最重要的一个点。


observe(LifecycleOwner , Observer)方法内部首先对observer进行了去重校验,如果之前已经用同个observer对象调用了observe(LifecycleOwner,Observer)方法,而LifecycleOwner不是同一个对象,则直接抛出异常。即一个Observer只允许和单个LifecycleOwner进行绑定。因为如果允许一个Observer同时和多个不同的LifecycleOwner进行绑定的话,这可能会导致当LiveData 数据发生变化时,处于RESUMED状态的LifecycleOwner和即将处于DESTROYED状态的另一个LifecycleOwner都会收到数据回调,而这破坏了observe(LifecycleOwner,Observer)所期望的生命周期安全。

 @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        //限定只能在主线程调用 observe 方法
        assertMainThread("observe");
        //当 Lifecycle 已经处于 DESTROYED 状态时,此时进行 observe 是没有意义的,直接返回
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        //根据传入参数构建一个新的代理 Observer
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        //将 observer 作为 key,wrapper 作为 value 进行存储
        //当 mObservers 不包含该 key 时,调用 putIfAbsent 会返回 null
        //当 mObservers 已包含该 key 时,调用 putIfAbsent 不会存储 key-value,并会返回之前保存的 value
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            //走到此步,说明之前 LiveData 内部已经持有了 observer 对象,且该 observer 对象已经绑定了其它的 LifecycleOwner 对象
            //此时直接抛出异常
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            //observer 之前已经传进来过了,此处直接返回
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
    }

上面的代码使用到了LifecycleBoundObserver,它是抽象类ObserverWrapper的实现类。ObserverWrapper用于包装外部传进来的Observer对象,为子类定义好特定的抽象方法和共用逻辑,主要是提供了共用的状态分发函数。

 private abstract class ObserverWrapper {
     //外部传进来的对 LiveData 进行数据监听的 Observer
        final Observer<? super T> mObserver;
     //用于标记 mObserver 是否处于活跃状态
        boolean mActive;
     //用于标记 Observer 内最后一个被回调的 value 的新旧程度
        int mLastVersion = START_VERSION;
        ObserverWrapper(Observer<? super T> observer) {
            mObserver = observer;
        }
     //用于获取当前 Lifecycle 是否处于活跃状态
        abstract boolean shouldBeActive();
     //用于判断 mObserver 是否和 LifecycleOwner(即 Lifecycle)有绑定关系
        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }
     //移除 mObserver
        void detachObserver() {
        }
        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            //判断当前 LiveData 所有的 Observer 是否都处于非活跃状态
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            //更新 LiveData 当前所有处于活跃状态的 Observer 的数量
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                //如果 LiveData 处于活跃状态的 Observer 数量从 0 变成了 1,
                //则回调 onActive 方法
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                //如果 LiveData 处于活跃状态的 Observer 数量从 1 变成了 0,
                //则回调 onInactive 方法
                onInactive();
            }
            if (mActive) {
                //如果 mObserver 变成了活跃状态,则向其回调新值
                dispatchingValue(this);
            }
        }
    }

ObserverWrapper一共有两个子类:LifecycleBoundObserver和AlwaysActiveObserver,两者的差别就在于是否和生命周期相绑定。


LifecycleBoundObserver也实现了LifecycleEventObserver接口,从而可以收到Lifecycle的每次生命周期事件切换时的事件回调。


LifecycleBoundObserver的整个事件流程是这样的:


1、Lifecycle的生命周期发生变化,从而回调了onStateChanged函数

2、onStateChanged函数首先判断Lifecycle是否已处于DESTROYED状态,是的话则直接移除Observer,整个回调流程结束,否则则继续以下流程

3、onStateChanged调用了activeStateChanged()函数,activeStateChanged()函数判断Lifecycle的活跃状态是否发生了变化,如果从非活跃状态切换到了活跃状态,是的话则调用dispatchingValue()函数来分发值,最终再根据ObserverWrapper内部的value版本号mLastVersion来判断是否有新值需要向其回调,是的话则向其回调新值,否则则返回

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() {
            //只有当 Lifecycle 的当前状态是 STARTED 或者 RESUMED 时
            //才认为 Lifecycle 是处于活跃状态
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }
     //LifecycleEventObserver 的实现方法
     //当 Lifecycle 的生命周期状态发生变化时就会调用此方法
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            //如果 Lifecycle 已经处于 DESTROYED 状态了,则主动移除 mObserver
            //这就是 LiveData 可以避免内存泄露最重要的一个点
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }
        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }
        @Override
        void detachObserver() {
            //移除 mObserver
            mOwner.getLifecycle().removeObserver(this);
        }
    }

二、非生命周期安全的observeForever


observeForever()函数的方法签名如下所示。observeForever()函数本身不会考虑外部所处的生命周期状态,只要数据发生变化时就会进行数据回调,因此observeForever()函数是非生命周期安全的。


observeForever()内部的逻辑也是先对observer进行了去重校验,如果之前已经先用该observer对象调用了observe(LifecycleOwner,Observer)方法,则直接抛出异常。因为如果允许observer同时调用observeForever()和observe()函数,则当数据发生变化时,这可能会造成Lifecycle处于DESTROYED状态时还进行了数据回调,而这破坏了observe(LifecycleOwner,Observer)所期望的生命周期安全。

 @MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
        //限定只能在主线程调用 observe 方法
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing instanceof LiveData.LifecycleBoundObserver) {
            //会走到这一步,是因为之前已经先用该 observer 对象调用了 observe(LifecycleOwner,Observer)
            //这里直接抛出异常
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            //如果之前已经添加过 observer 对象了的话,则直接返回
            return;
        }
        //主动触发 activeStateChanged 函数,因为当前 LiveData 可能已经被设置值了
        wrapper.activeStateChanged(true);
    }

上面代码使用到了AlwaysActiveObserver,它也是抽象类ObserverWrapper的实现类,其shouldBeActive()返回值固定为true,意味着只要有数据变化都会进行回调。所以使用observeForever()函数一定要在过后主动移除Observer,避免内存泄露和NPE。

 private class AlwaysActiveObserver extends ObserverWrapper {
        AlwaysActiveObserver(Observer<? super T> observer) {
            super(observer);
        }
        @Override
        boolean shouldBeActive() {
            //使其固定返回 true,则意味着只要有数据变化就都进行数据回调
            return true;
        }
    }

三、removeObserver

LiveData开放了两个方法用于添加Observer,那么自然会有removeObserver的方法。removeObserver的方式一共有两种,逻辑都比较简单。

 //移除指定的 Observer 对象
    @MainThread
    public void removeObserver(@NonNull final Observer<? super T> observer) {
        assertMainThread("removeObserver");
        ObserverWrapper removed = mObservers.remove(observer);
        if (removed == null) {
            return;
        }
        removed.detachObserver();
        removed.activeStateChanged(false);
    }
    //通过循环遍历移除所有和特定 LifecycleOwner 绑定的 Observer 对象
    @SuppressWarnings("WeakerAccess")
    @MainThread
    public void removeObservers(@NonNull final LifecycleOwner owner) {
        assertMainThread("removeObservers");
        for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {
            if (entry.getValue().isAttachedTo(owner)) {
                removeObserver(entry.getKey());
            }
        }
    }

/ 更新LiveData的值 /

更新LiveData的值的方法一共有两个,分别是:

setValue(T value)

postValue(T value)

1、setValue

setValue(T)函数被限定在只能主线程进行调用。

 private volatile Object mData;
    private int mVersion;
 @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
     //更新当前 value 的版本号,即 value 的新旧程度
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

dispatchingValue()函数设计得比较巧妙,用两个全局的布尔变量mDispatchingValue和mDispatchInvalidated就实现了新旧值判断、旧值舍弃、新值重新全局发布的逻辑。


其中需要注意mObservers的遍历过程,由于每遍历到一个item都会检查一次当前的value是否已经过时,是的话则中断遍历,所以是存在仅有部分Observer收到值的情况。


而有一个我比较疑惑的点是:从逻辑上看dispatchingValue()函数只会在主线程进行调用,那么dispatchingValue()一定是会在执行完毕后才被再次执行,不存在多线程同时调用的情况,且dispatchingValue()函数内部也没有嵌套调用自己,那么此时mDispatchingValue和mDispatchInvalidated两个变量就显得没有意义了,希望了解其作用的同学可以留言指教下。

//用于标记当前是否正处于向 mObservers 发布 value 的过程
 private boolean mDispatchingValue;
 //用于标记当前正在发布的 value 是否已经失效
 //在 value 还未向所有 Observer 发布完成的时候,新 value 已经到来,此时旧 value 就是处于失效状态
    @SuppressWarnings("FieldCanBeLocal")
    private boolean mDispatchInvalidated;
 //initiator 为 null 则说明需要遍历回调整个 mObservers
 //initiator 不为 null 则说明仅回调 initiator 本身
 @SuppressWarnings("WeakerAccess") /* synthetic access */
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            //如果当前正处于向 mObservers 发布 mData 的过程中(即 mDispatchingValue 为 true)
            //则将 mDispatchInvalidated 置为 true,用于标明有新值到来,正在回调的值是已经过时的了
            mDispatchInvalidated = true;
            return;
        }
        //用于标记当前正处于向 mObservers 发布 mData 的过程中
        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) {
                        //如果 mDispatchInvalidated 为 true,则中断继续遍历过程
                        //用新值来重新循环一遍
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
 @SuppressWarnings("unchecked")
    private void considerNotify(ObserverWrapper observer) {
        //如果 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.
        //此处判断主要是为了照顾 LifecycleBoundObserver
        //由于 Lifecycle 有可能状态值 State 已经切换到了非活跃状态,但 LifecycleBoundObserver 还未收到事件通知
        //所以为了避免意外情况,此处主动检查 observer 的活跃状态并判断是否需要更新其活跃状态
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //根据 observer 本部的 value 版本号 mLastVersion 来决定是否需要向其进行回调
        //为了避免重复向某个 observer 回调值,所以此处需要判断下
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

2、postValue

postValue(T)函数不限定调用者所在线程,不管是主线程还是子线程都可以调用,因此是存在多线程竞争的可能性的,postValue(T)函数的重点旧在于需要理解其从子线程切换到主线程之间的状态变化。


由于LiveData值回调的行为是会固定放在主线程完成的,所以postValue(T)函数将值回调的逻辑放到Runnable中再Post给Handler,最终交由主线程来执行,因此从调用postValue(T)函数到Runnable被执行之间是会有段时间差的,此时其它线程可能又调用了postValue(T)函数传递了新值。


在mPostValueRunnable被执行前,所有通过postValue(T)函数传递的value都会被保存到变量mPendingData上,且只会保留最后一个,直到mPostValueRunnable被执行后mPendingData才会被重置,所以使用 postValue(T) 函数在多线程同时调用或者单线程连续调用的情况下是存在**丢值(外部的 Observer 只能接收到最新值)**的可能性的。

  @SuppressWarnings("WeakerAccess") /* synthetic access */
    final Object mDataLock = new Object();
 @SuppressWarnings("WeakerAccess") /* synthetic access */
 //mPendingData 的默认值
 //当 mPendingData 等于 NOT_SET 时说明当前 LiveData 没有值需要通过 postValue 回调
    static final Object NOT_SET = new Object();        
    volatile Object mPendingData = NOT_SET;
 //用于在主线程对值进行回调
 private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                //通过加锁可以确保 newValue 指向的是当前最新值
                newValue = mPendingData;
                //重置 mPendingData
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };
 protected void postValue(T value) {
        boolean postTask;
        //加锁以保证 mPendingData 值能够一直指向最新值
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        //如果 postTask 为 false,则说明当前有旧值需要通过 postValue 进行回调
        //因为 postValue 可以在子线程调用,而 Observer 的 onChanged(value) 方法肯定是要在主线程被调用
        //从子线程切到主线程之间是有段时间间隔的
        //等到 mPostValueRunnable 真正执行时让其直接发送最新值 mPendingData 即可,所以此处直接返回
        if (!postTask) {
            return;
        }
        //向主线程发送一个 runnable,主要是为了在子线程调用 postValue,在主线程进行值回调
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

/ 判断Value是否是新值 /

此章节再来介绍下LiveData是如何判断是否需要向Observer回调值的。

先来说下为什么需要进行这个判断,而不能每次接受到新值时都直接进行回调,这是基于以下几个原因的:


1、observeForever()函数是只要接收到value就会马上运行回调逻辑,这个过程也不是马上就能完成(因为还需要Post到主线程运行), 与observe()函数根据Lifecycle的变化再来进行回调的时机的先后顺序具有不确定性。所以需要判断进行回调的value对于Observer来说是否是新值,避免重复回调

2、外部可能在不同阶段先后调用了多次observe()函数或者observeForever()函数,此时也需要仅在没有对Observer传过值的情况下进行回调,避免重复回调


LiveData在其构造函数内部就开始了新旧值的记录,主要是根据一个整数mVersion来记录当前value的版本号,即新旧程度。

static final int START_VERSION = -1;
    private int mVersion;
    /**
     * Creates a LiveData initialized with the given {@code value}.
     *
     * @param value initial value
     */
    public LiveData(T value) {
        mData = value;
        mVersion = START_VERSION + 1;
    }
    /**
     * Creates a LiveData with no value assigned to it.
     */
    public LiveData() {
        mData = NOT_SET;
        mVersion = START_VERSION;
    }

而mVersion的改变只会在setValue()接收到新值时才会递增加一,从而表明所有Observer内部的data均已过时,需要重新回调。由于postValue()函数最终还是会调用setValue()函数来完成回调逻辑,所以只需要看setValue()函数即可。

 @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

当对Observer进行回调时,也需要先判断下value对于Observer来说是否是新值,是的话则先保存当前value的版本号mVersion再进行回调。

 @SuppressWarnings("unchecked")
    private void considerNotify(ObserverWrapper observer) {
        //如果 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.
        //此处判断主要是为了照顾 LifecycleBoundObserver
        //由于 Lifecycle 有可能状态值 State 已经切换到了非活跃状态,但 LifecycleBoundObserver 还未收到事件通知
        //所以为了避免意外情况,此处主动检查 observer 的活跃状态并判断是否需要更新其活跃状态
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //根据 observer 本部的 value 版本号 mLastVersion 来决定是否需要向其进行回调
        //为了避免重复向某个 observer 回调值,所以此处需要判断下
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

下面是我整理出来的一些资料,想要更多可以点击我的github从而了解更多进阶的可能哦。

相关文章
|
6月前
|
存储 移动开发 数据库
构建高效Android应用:探究LiveData和ViewModel的最佳实践
【4月更文挑战第20天】 在动态演化的移动开发领域,构建一个既响应迅速又能够在用户界面保持稳定的Android应用是至关重要的。近年来,随着Android架构组件的推出,特别是LiveData和ViewModel的引入,开发者得以更有效地管理应用状态并优化用户界面的响应性。本文将深入探讨LiveData和ViewModel的实现机制,并通过案例分析展示如何结合它们来构建一个高效且健壮的Android应用架构。我们将重点讨论如何通过这些组件简化数据绑定过程、提高代码的可维护性和测试性,同时确保用户界面的流畅性。
|
6月前
|
安全
一道面试题:介绍一下 LiveData 的 postValue ?
一道面试题:介绍一下 LiveData 的 postValue ?
79 0
|
4月前
LiveData和ViewModel源码学习
LiveData和ViewModel源码学习
|
6月前
|
前端开发
MVVM LiveData+DataBinding+Lifecycle+ViewModel架构
MVVM LiveData+DataBinding+Lifecycle+ViewModel架构
64 1
|
6月前
|
数据库 Android开发 开发者
实现高效安卓应用:探究LiveData和ViewModel的最佳实践
【4月更文挑战第19天】 在构建响应式的Android应用程序时,LiveData和ViewModel是两个核心组件。它们不仅提供了数据持有和界面更新的机制,还促进了组件间的解耦。本文将深入探讨如何通过结合LiveData和ViewModel来优化应用架构,提升用户体验,并确保数据的一致性和生存期管理。我们将透过实际案例分析,揭示这些技术如何协同工作以应对复杂的UI场景,并展示如何在实际项目中实施这些最佳实践。
|
6月前
|
存储 前端开发 JavaScript
useReducer的使用场景?
useReducer的使用场景?
169 0
|
存储 缓存 前端开发
学会使用LiveData和ViewModel,我相信会让你在写业务时变得轻松🌞
当你学会如何使用LiveData和ViewModel后,你会发现,世界变得简单了... 在2017年,那时,观察者模式有效的简化了开发,但是诸如RxJava一类的库有一些太过复杂,学习成本
|
XML 缓存 Java
ViewBinding 的本质
ViewBinding 的本质
168 0
ViewBinding 的本质
|
Android开发
Livedata用的爽吗,StateFlow你也应该了解一下
Livedata用的爽吗,StateFlow你也应该了解一下
755 0
Livedata用的爽吗,StateFlow你也应该了解一下
Livedata源码详细解析-面试这么讲就ok
Livedata源码详细解析-面试这么讲就ok
286 0
Livedata源码详细解析-面试这么讲就ok