一、概念
一个可以被观察的数据持有类,LiveData是只读版本,MutableLiveData是可读可写版本,。
- 用来更新UI:setValue()和postValue()更新值都是在主线程执行,因此观察者的onChange()回调在主线程。
- 生命周期感知:可以感知 Activity、Fragment或Service 等组件的生命周期,无需手动处理,UI层只需要对数据进行监听。
- 单个最新值:更新UI需要使用最新数据,过时的数据应该被忽略。并且只会在界面处于活跃状态(onStart和OnResume)收到通知(非活跃状态更新UI无意义浪费资源)。
- 自动取消订阅:Observers 是绑定到 Lifecycle 对象上的,当与其关联的 lifecycle 被销毁的时候,它们会自动被清理。开发者无需手写模板代码,降低内存泄漏风险。
- 粘性事件:当按下Button弹出Snackerbar,此时设备配置改变(例如屏幕旋转),之前的View会销毁然后重建,新的View会重新订阅,那么会再次消费事件弹出Snackerbar。
- 默认不防抖:更新的值和上次相同,onChange()依然会再次调用。可以使用Transformations的distinctUntilChanger()、SingleLiveEvent解决。
二、简单使用
2.1 添加依赖
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
2.2 创建、更新
只能创建读写版本的 MutableLiveData,可以转换成只读版本的 LiveData,根据实际需求暴露不同类型收窄功能。
| MutableLiveData() | public MutableLiveData() 创建读写版本,是否设置默认值,默认为null。 |
| postValue() | public void postValue(T value) 更新值,子线程调用。 |
| setValue() | public void setValue(T value) 更新值,主线程调用。 |
| getValue() | public @Nullable T getValue() 获取值。 |
ViewModel {
private val _num = MutableLiveData(0) //私有化可读可写版本
val num: LiveData<Int> = _num //对外暴露只读版本
fun fetchData() {
_num.value = 1 //读写
}
}
2.3 观察
| observe() | public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) 具有生命周期感知,处于活跃状态即 START 、RESUME 时才会接收事件,处于 DESTROYED 时观察者会被移除。 |
Activity {
onCreate() {
observeLiveData()
}
//聚合多个 LiveData 一起观察
fun observeLiveData() {
viewModel.num.observe(this) { num ->
textView.text = num
}
}
}
三、进阶
3.1 转换 Transformations
通过 Transformations 类调用太麻烦,推荐使用 LiveData 的扩展函数版本。
| map | public fun <X, Y> LiveData<X>.map( 对数据源中的每个值应用转换函数,将得出的新值再派发给观察者。 |
| switchMap | public fun <X, Y> LiveData<X>.switchMap( 不要对一个返回LiveData的函数进行观察,每次调用该函数都会返回新的实例,UI组件需要取消原先的注册,再对新实例重新注册。应该创建一个LivaData用来存储输入值,通过 switchMap 调用该函数返回新的LiveData。 |
| distinctUntilChanged | 更新的值和当前值相同则不会回调onChange()。 |
map
//把原值 User 改成 User.name
val userLiveData: LiveData<User> = MutableLiveData(User())
val nameLiveData: LiveData<String> = Transformations.map(userLiveData) { user ->
user.name
}
switchMap
//不要这样做
fun getPostCode(address: String): LiveData<String> {}
viewModel.getPostCode("").observe(this) {...}
//而是这样做
private val addressLiveData = MatableLiveData("") //私有化输入源
val postCodeLiveData = addressLiveData.switchMap { address ->
repository.getPostCode(address) //传值给返回LiveData的函数
}
fun setAddress(address: String) { //外部调用
addressLiveData.value = address
}
3.2 合并 MediatorLiveData
用来合并多个LivaData数据源,任何一个数据源发生变化都会触发。例如分别为本地和网络两个数据创建LiveData,通过MutableLiveData调用addSource()将两个LiveData数据源添加进去,最后订阅即可。
| addSource() | public <S> void addSource( @NonNull LiveData<S> source, //数据源 LiveData @NonNull Observer<? super S> onChanged //数据源变化时回调 ) 添加 LiveData 源。 |
| removeSource() | public <S> void removeSource( @NonNull LiveData<S> toRemote ) 移除 LiveData 源。 |
//ViewModel
private val local = MutableLiveData<String>()
private val remote = MutableLiveData<String>()
private val _combine = MediatorLiveData<String>().apply {
addSource(local) { value = it }
addSource(remote) { value = it }
}
val combine: LiveData<String> = _combine
//UI
viewModel.combine.observe(this) { value -> }
2.4 异步生产
LifeCycle v2.20 版本后,可以在创建 LiveData 的同时,使用协程定义值的异步生产方式(由于只读无法后期更新,适用于一次性数据),就像 Flow 构建器一样只是没有那么多操作符可用。省去了对只读限制的封装,UI中直接观察ViewModel的该属性。
| public fun <T> liveData( |
ViewModel {
//直接调用挂起函数赋值
val num1 = liveData { emit(getData()) }
//还可以指定线程,单独写耗时操作
val num2: LiveData<Int> = liveData(Dispatchers.IO) {
emit(5)
delay(1000)
emit(3)
}
//从另一个LivaData获取更新结果
val aa = MutableLiveData(10)
val bb = liveData{ emitSource(aa) }
suspend fun getData(): Int = withContext(Dispatchers.IO) { 3 }
//与 Transformations 结合使用
private val userId: LiveData<String> = MutableLiveData()
val user = userId.switchMap { id ->
liveData(Dispatchers.IO) {
emit(database.loadUserById(id))
}
}
}
2.5 Flow 转 LiveData
| public fun <T> Flow<T>.asLiveData( context: CoroutineContext = EmptyCoroutineContext,//区块所执行的协程上下文,默认+Main.immediate timeoutInMs: Long = DEFAULT_TIMEOUT //没有观察者后,多少毫秒后取消区块,默认5s ): LiveData<T> |
ViewModel {
val num1: LiveData<Int> = liveData { DataSource().getDataFlow.collect { emit(it) } }
val num2: LiveData<Int> = DataSource().getDataFlow.asLiveData() //简写
}
DataSource {
val getDataFlow: Flow<Int> = flow { repeat(3) { emit(it) } }
}
2.6 判断
| removeObserve ( ) | 移除当前所有观察者。 |
| hasObserve ( ) | 如果有观察者。 |
| hasActiveObserve ( ) | 如果有活跃的观察者(UI处于onStart或者onResume)。 |
4503

被折叠的 条评论
为什么被折叠?



