Jetpack学习之 LiveData

LiveData 是 Google 推荐的基于观察者的数据持有者,可以认为是一个轻量级的RxJava。
一般来说不会单独使用,会和其他组件一起搭配,最常用的就是 ViewModel 了。

1. 概述

1.1 什么是LiveData

官方定义:

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData具有生命周期感知能
力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可
确保 LiveData仅更新处于活跃生命周期状态的应用组件观察者。

简单可以理解为一个 Observable ,同时能够感知生命周期

如果搭配ViewModel,那么 ViewModel 就是 LiveData 的数据源,当数据更新后, LiveData 就会通知它的所有观察者。 与 RxJava 的方法不同的是, LiveData 并不是通知所有观察者,他只会通知处于 Active 状态的观察者,如果一个观察者处于 Paused 状态或 Destroyed 状态,那么它将不会受到通知。

1.2 为什么使用LiveData

  1. 解耦
  2. 避免内存泄漏

Activity、Service、Fragment可以安全的观察LiveData对象,而且不用在 onPaused 或者 onDestroy 方法中去解订阅。
一旦观察者恢复 resumed 状态, 它将会重新收到 LiveData 的最新数据。

2. 使用

这里省去导入流程,可以看 Jetpack学习之 Lifecycle

2.1 基本用法

LiveData 是一个抽象类, 它有一个比较简单又常用的实现类:MutableLiveData, 这里举个栗子:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val mutableLiveData = MutableLiveData<String>()
        // 1
        mutableLiveData.observe(this, Observer { 
            Log.d(TAG, "onChanged: $it")
        })
        // 2
        mutableLiveData.postValue("Hi Noel~")
    }
}

注释1:observe() 有两个参数,分别是 LifecycleOwnerObserver<T> 也就是被观察者。
Kotlin代码的lambda表达式省略掉了其实现方法体,也就是 onChanged(@Nullable final String s) 方法,他能够在数据变化时,回调这个方法

注释2:postValue() 会在主线程更新数据,这样就会得到打印的结果,如下所示:
在这里插入图片描述
这里需要注意的是:

  • 将更新界面的LiveData对象存储在ViewModel中,而不是将其存储在Activity或Fragment中:
    (1)避免Activity或Fragment过于庞大,分离 ui 和数据
    (2)将LiveData实例与特定Activity实例分离开,使LiveData对象在配置更改后继续存在
  • 在onCreate方法中开始观察LiveData对象
    不要在onResume方法中进行调用 observe() ,因为会出现多次调用的问题。
    确保Activity或Fragment变为活跃状态后具有可以立即显示的数据,因为应用组件处于STARTED 状态,就会从它正在观察的 LiveData 对象接收最新值
  • 当组件处于DESTROY状态时会自动取消订阅
  • 除了使用 postValue(),还可以使用 setValue(),区别是后者必须在主线程调用。如果需要在子线程中更新 LiveData, 可以使用 postValue 方法。

2.2 更改 LiveData 中的数据

2.2.1 Transformations.map 方法

和 RxJava 一样,我们可以对数据分发到指定对象之前,给它map一下,转化成另一种数据,比如下面代码,LiveData 原数据是 Int 型, 通过 map 转化成 String 类型(或则任何数据):

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val mutableLiveData = MutableLiveData<Int>()
        mutableLiveData.observe(this, Observer {
            Log.d(TAG, "onChanged1: $it")
        })

        val transformationsLiveData = Transformations.map(
            mutableLiveData
        ) { input ->
            ("$input go")
        }

        transformationsLiveData.observe(this, Observer {
            Log.d(TAG, "obChanged2: $it")
        })
        mutableLiveData.postValue(1)
    }

2.2.2 Transformations.switchMap 方法

和 map 不同, switchMap返回的结果必须是一个 LiveData 数据,而且它可以通过一个 Boolean 值来选择监听对象

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mutableLiveData1 = MutableLiveData()
        mutableLiveData2 = MutableLiveData()
        // 1
        liveDataSwitch = MutableLiveData()

        // 如果是true,选择监听1,否则监听2
        val transformedLiveData = Transformations.switchMap(liveDataSwitch) {
            if (it) mutableLiveData1 else mutableLiveData2
        }

        transformedLiveData.observe(this, Observer {
            Log.d(TAG, "onChanged: $it")
        })
        liveDataSwitch.postValue(false)
        mutableLiveData1.postValue("noel")
        mutableLiveData2.postValue("bye")
    }

注释1:创建一个 MutableLiveData<Boolean> 来控制切换并复制给 liveDataSwitch
当 liveDataSwitch 的值为 true 时, 返回 mutableLiveData1, 否则返回 mutableLiveData2
这样最终输出的结果为2

2.2.3 MediatorLiveData合并数据源

MediatorLiveData 继承自 MutableLiveData, 它的作用是可以收集多个 LiveData。 如果其中一个 LiveData 数据源发生变化,那么也会通知到 MediatorLiveData

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val mutableLiveData1 = MutableLiveData<String>()
        val mutableLiveData2 = MutableLiveData<String>()
        // 创建一个用于合并数据源的LiveData
        val liveDataManager = MediatorLiveData<String>()

        // 添加数据 LiveData1, 并监听其变化
        liveDataManager.addSource(mutableLiveData1) {
            Log.d(TAG, "onChanged 1: $it")
        }

        // 添加数据 LiveData2, 并监听其变化
        liveDataManager.addSource(mutableLiveData2) {
            Log.d(TAG, "onChanged 2: $it")
        }

        liveDataManager.observe(this, Observer {
            Log.d(TAG, "onChanged Data: $it")
        })

        mutableLiveData1.postValue("i always like u")
        liveDataManager.postValue("thank u")
    }

打印结果:
在这里插入图片描述

2.2.4 自定义LiveData

我们可以自定义一个 LiveData, 因为会有观察者来观察这个 LiveData, 所以观察者处于 STARTED 或者 RESUMED 时,LiveData 将会处于 Activity状态,这个时候通过实现 onActive() / onInactive() 来通知观察者。

下面是个例子,我们设定一个可以变化的数据类:

class ExtStringLiveData private constructor() : LiveData<String>() {

    companion object {
        private const val TAG = "ExtStringLiveData"

        private var sInstance: ExtStringLiveData? = null

        @MainThread
        fun get(): ExtStringLiveData? {
            if (sInstance == null) {
                sInstance = ExtStringLiveData()
            }
            return sInstance
        }
    }

    // 观察者处于活跃状态, 则通知它
    override fun onActive() {
        Log.d(TAG, "onActive")
        // 这里的数据是写死的, 在实际项目中, 可以以监听器不断输出数据
        value = "if u find me again, i will with u again"
    }

    override fun onInactive() {
        Log.d(TAG, "onInactive")
        // 这里的数据是写死的, 在实际项目中, 可以以监听器不断输出数据
        // 在这之后, 就不会再想观察者发送数据直到观察者恢复active状态, 所以这一里在更改数据就不会通知了
        value = "because I'm starting to regret it"
    }
}

然后在 MainActivity 去监听它:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        ExtStringLiveData.get()?.observe(this, Observer {
            Log.d(TAG, it)
        })
    }

打印结果为:

在这里插入图片描述
而在 LiveData 的 onInactive() 中更改的string数据, MainActivity 就打印不出来了。

3. 原理

3.1 LiveData 如何观察生命周期变化

因为组件都是通过调用 LiveData.observe(LifecycleOwner, Observer<? super T>) 进行监听,所以了解 Livecycle 的同学肯定就知道了其中的奥秘。我们来看看它的源码吧:

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        // 1
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            return;
        }
        // 2
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        // 3
        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;
        }
        // 4
        owner.getLifecycle().addObserver(wrapper);
    }

注释1:如果当前声明周期是 DESTORYED, 则拒绝注册

注释2:新建一个 LifecycleBoundObserver 实例,并传入相应参数

注释3:mObservers 的类型是 SafeIterableMap<Observer<? super T>, ObserverWrapper>mObservers,key是观察者,value是注释2中创建的对象。
在这个map中的putIfAbsentput 是有区别的,如果传入的 key 存在,就返回value,而不替换,如果 key 不存在,则添加进去,并返回null。

注释4:如果注释3的map中没有数据, 则调用 Lifecycle.addObserver,传入的是 LivecycleBoundObserver。 看来这个类比较重要,我们有必要去了解它的构造和作用。

3.2 LiveData 的 observe 方法回调

来看看 LivecycleBoundObserver ,它是 LiveData 的内部类:

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull final LifecycleOwner mOwner;
        ...
        @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;
                // 1
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }

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

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

该类继承了 ObserverWrapper 类,重写了 shouldBeActive() 方法, 它的作用是用来判断当前传入的组件是否是 Active的, Active状态包括 STARTED 、 RESUMED

该类还实现了 LifecycleEventObserver 接口,当组件状态发生变化的时候, 会调用 onStateChanged() ,当组件处于 DESTORYED 状态是,会调用 removeObserver() 来移除 observer。
这也就是为什么,LiveData 不会给那些 Inactive 的组件发通知。

注释1: 调用父类的 activeStateChanged(),我们来看看父类:

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

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

        abstract boolean shouldBeActive();

        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }

        void detachObserver() {
        }

        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            changeActiveCounter(mActive ? 1 : -1);
            if (mActive) {
                // 1
                dispatchingValue(this);
            }
        }
    }

ObserverWrapper 是一个抽象类,它包装了一个 Observer, activeStateChanged 会看 传进来的状态是否和此前状态是否相同,不同则,则执行 changeActiveCounter() ,来更新一下当前LiveData 观察者的活跃与非活跃的数量, 来决定调用 onActive()onInactive()

其次,如果当前是 Active 状态,则调用注释1的 dispatchingValue() 方法

    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() 方法:

    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        // 1
        observer.mObserver.onChanged((T) mData);
    }

即使是到了这里,也会一直在判断当前组件的状态,非常严格呢。

如果所有更新条件都满足,则会调用 Observer 的 onChanged() , 也就从这里回调出去了~

3.3 postValue 方法

我们来看看调用 postValue() / setValue() 之后,LiveData 做了什么事情, 这里以 postValue 为例,来看看代码~

    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        // 1
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    
    private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            // 2
            setValue((T) newValue);
        }
    };

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

注释1、2:做一个线程切换,切换到主线程中,并用线程安全的 synchronized()

注释3:确定当前线程是主线程,在非主线程中直接调用该方法会crash

注释4: 调用 dispatchingValue ,之后就是 considerNotify() 来通知观察者啦~

3.4 总结

  • LiveData 基于观察者模式实现和 LifecyclerOwner 绑定后能感知生命周期
  • 只有处于活跃状态的 Owne r才会接收到数据变化的通知,Owner从非活跃状态变为活跃状态,会接收到新的数据通知
  • Owner进入DESTROY状态会自动 remove Observer,不会担心内存泄露问题,如果希望一直接收到通知,可以使用 observeForever()方法
  • 主线程使用 setValue() 、工作线程使用 postValue() 进行数据更新

参考文章

《Android进阶指北》Android Jetpack架构组件
LiveData官方文档

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值