LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
【本系列文章(JAVA/KOTLIN)演示案例均存储在github存储库ArchitecturalComponentExample中】
LiveData的优势
在正式使用之前,我们先来了解下其优势(即我们为什么要使用它),以下引用取自官方文档:
确保界面符合数据状态
LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知 Observer 对象。您可以整合代码以在这些 Observer 对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。
不会发生内存泄漏
观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。
不会因 Activity 停止而导致崩溃
如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
不再需要手动处理生命周期
界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
数据始终保持最新状态
如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。
适当的配置更改
如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
共享资源
您可以使用单例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象。如需了解详情,请参阅扩展 LiveData。
引入依赖
LiveData作为生命周期感知组件,它的依赖包也是 lifecycle族系,通常的,我们常常将LiveData配合ViewModel使用,当然你也可以单独使用LiveData依赖。
1 | def lifecycle_version = "2.3.0" |
此文演示项目为ViewModel+LiveData,如有对ViewModel不了解的可以通过【官方文档】或【Jetpack之界面数据存储组件-ViewModel】具体了解。
请按照以下步骤使用 LiveData 对象:
- 创建 LiveData 的实例以存储某种类型的数据。这通常在 ViewModel 类中完成。
- 创建可定义 onChanged() 方法的 Observer 对象,该方法可以控制当 LiveData 对象存储的数据更改时会发生什么。通常情况下,您可以在界面控制器(如 Activity 或 Fragment)中创建 Observer 对象。
- 使用 observe() 方法将 Observer 对象附加到 LiveData 对象。observe() 方法会采用 LifecycleOwner 对象。这样会使 Observer 对象订阅 LiveData 对象,以使其收到有关更改的通知。通常情况下,您可以在界面控制器(如 Activity 或 Fragment)中附加 Observer 对象。
创建LiveData
创建LiveData的方式非常简单,你只需要直接new出他的子类并传入你想要观察的数据类型泛型即可,LiveData提供setValue(T t) & postValue(T t)
用以更新值, 可以使用T getValue()
获取值:
1 | MutableLiveData<Integer> price = new MutableLiveData<>(); |
观察LiveData
在大多数情况下,应用组件的 onCreate() 方法是开始观察 LiveData 对象的正确着手点,原因如下:
- 确保系统不会从 Activity 或 Fragment 的 onResume() 方法进行冗余调用。
- 确保 Activity 或 Fragment 变为活跃状态后具有可以立即显示的数据。一旦应用组件处于 STARTED 状态,就会从它正在观察的 LiveData 对象接收最新值。只有在设置了要观察的 LiveData 对象时,才会发生这种情况。
LiveData订阅observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer)
需要两个参数,生命周期拥有者LifecycleOwner和观察者Observer。
一般的,继承自AndroidX包中的Activity/Fragment组件(api >= 26)已自行实现LifecycleOwner。
在未强调说明的情况下,本文代码块均保持使用Java8特性。
1 | // 建立订阅关系 |
我们来看一下执行效果:
1 | 订阅数据变化👉 0 |
当我们改变被观察的值时,我们的观察者也如预期被通知到了,这样便实现了最简LiveData数据观察流程(详细代码【Java示例请参见此处】、【Kotlin示例请参见此处】)。
扩展LiveData
你可以继承LiveData自行实现LiveData的数据变更状态的分发,已演示项目为例:
1 | public class MyPriceLiveData extends LiveData<Integer> { |
我们像先前一样使用:
1 | // ViewModel中 |
我们运行查看结果,并做息屏亮屏操作:
1 | // 点击按钮 |
我们的扩展LiveData会在息屏/亮屏时触发 onInactive()/ onActive()
回调,从而执行我们的自定义实现代码。
转换 LiveData
LiveData为我们提供了数据转换功能,包含Transformations.map()
、Transformations.switchMap()
两种方式,其调用方式一致,区别在于 map() 的第二个参数(可理解为转换器)需返回泛型T,而switchMap() 的第二个参数(可理解为转换器)需返回LiveData
map()转换:
1 | // ViewModel中 |
我们执行观察结果:
1 | 转换数据(map)👉 0块刚刚好 |
switchMap()转换:
1 | // 转换前的LiveData |
调用方式与map()一致,你可以对转换后的LiveData观测,也可以对转换结果LiveData观测,此处省略,我们来观察其执行结果:
1 | 我是商家想法的订阅:0穷鬼 |
对转换后的LiveData观测及以对转换结果LiveData观测均能收到响应。为判断2个LiveData是否观察的是同一个对象,我们将转换后的目标及结果改造为对象,观察其hashCode是否相等:
1 | // 转换后的目标LiveData |
执行观察结果打印:
1 | 订阅的Seller.hashCode() = 84056966 |
我们发现,转换后的目标LiveData及转换结果LiveData实际观察对象为同一个,不会为数据创建副本。
合并LiveData
MediatorLiveData 是 LiveData 的子类,允许您合并多个 LiveData 源。只要任何原始的 LiveData 源对象发生更改,就会触发 MediatorLiveData 对象的观察者。
首先我们需要定义一个合并LiveData源:
1 | MediatorLiveData<Object> mediatorLiveData = new MediatorLiveData<>(); |
并在使用时,为其添加观察的LiveData源:
1 | // 合并观察1 |
我们观察其执行结果:
1 | // 第一次触发 |
我们发现,在触发单个LiveData值变化时除了其本身LiveData的观察者被触发,合并数据的观察者也会被触发。
对于此API的应用场景,官方有提出以下场景:
例如,如果界面中有可以从本地数据库或网络更新的 LiveData 对象,则可以向 MediatorLiveData 对象添加以下源:
- 与存储在数据库中的数据关联的 LiveData 对象。
- 与从网络访问的数据关联的 LiveData 对象。
您的 Activity 只需观察 MediatorLiveData 对象即可从这两个源接收更新。
小节
LiveData 是生命周期相关的数据观察者,你可以通过自定义LiveData、使用map()及switchMap()转换LiveData源为你需要的LiveData源、你也可以合并观察不同的LiveData源的变化,这些方式基本能满足对一般数据观察的需求。