二、LiveData
1. 作用
• LiveData 一个可观测的数据持有类
• 数据可以被观察者订阅
• 能够感知组件(Fragment、Activity、Service)的生命周期
• 只有在组件出于激活状态才会通知观察者有数据更新
2.优势
• 确保UI和数据状态匹配
当数据发生改变的时候,会自动通知UI进行更新
• 避免内存泄漏
Observers 绑定到 Lifecycle 对象上,当与其关联的 lifecycle 被销毁的时候,它们会自动被清理
• 避免了由于 Activity 停止而导致的闪退
Observer 绑定的 Lifecycle 处于非活跃状态时,不会收到任何 LiveData 事件
• 不再需要手动处理生命周期
LiveData 具有生命周期感知能力,它会自动对这些进行管理
• 数据总处于最新状态
Lifecycle 由非活跃状态变为活跃状态时,它将收到最新的数据
• 系统配置更改时,进行数据的保存和恢复,及 UI 的恢复
配合 ViewModel 可以规避旋转屏幕等问题
• 资源共享
可以使用单例模式来扩展 LiveData,这样能达到数据变化的时候,通知所有的观察者
3. 使用
3.1. 创建 LiveData
• 创建 LiveData 实例,让其持有特定的数据类型
• 通常是将 LiveData 放在 ViewModel 中使用
// 1.创建 LiveData
private val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
3.2. 创建 Observe
• 创建 Observer 对象,并实现 onChanged()
,在此定义 LiveData 持有的数据改变时做何操作
• 可在此更新 UI ,一般 Observer 在 UI controller 中创建,比如 Activity 或者 Fragment
// 2.创建 Observe
val nameObserver = Observer<String> { newName ->
binding.data = newName
}
3.3. Observer 添加到 LiveData
• observe(LifecycleOwner owner, Observer observer)
• owner : LifecycleOwner对象,LiveData 能监听生命周期的能力来源
• observer : 监听器对象 Observer
// 3.Observer 添加到 LiveData
currentName.observe(this@MainActivity, nameObserver)
3.4. 改变 LiveData 值
• 在UI线程通过 value
改变 LiveData 值
• 在子线程通过 postValue()
修改 LiveData 值
// 点击时改变 LiveData 值
binding.button.setOnClickListener {
// 4.UI 线程通过 value 修改 LiveData 值
currentName.value = "2234"
}
// 点击时改变 LiveData 值
binding.button.setOnClickListener {
Thread {
var num = 0
while (num < 5) {
try {
Thread.sleep(1000)
} catch (e: InterruptedException) {
e.printStackTrace()
}
// 4.子线程通过 postValue() 修改 LiveData 值
currentName.postValue((++num).toString())
}
}.start()
}
4. 其他
4.1. 扩展 LiveData
• 如需观察者处于 active
状态时做操作,可通过继承 LiveData
或者 MutableLiveData
后复写onActive()
和onInactive()
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
private val stockManager = StockManager(symbol)
// setValue(T) 方法将更新 LiveData 实例的值,并将更改通知给任何活跃观察者。
private val listener = { price: BigDecimal ->
value = price
}
// 当 LiveData 对象具有活跃观察者时,会调用 onActive() 方法。
// 这意味着,您需要从此方法开始观察股价更新。
override fun onActive() {
stockManager.requestPriceUpdates(listener)
}
// 当 LiveData 对象没有任何活跃观察者时,会调用 onInactive() 方法。
// 由于没有观察者在监听,因此没有理由与 StockManager 服务保持连接。
override fun onInactive() {
stockManager.removeUpdates(listener)
}
}
4.2.转换 LiveData
-
Transformations.map()
• 可以通过Transformations
的map
操作符 修改数据
• 可以将数据转换为其他类型// ====== Transformations.map 处理 类型转换 ====== Transformations.map(currentName) { Function<String, String> { input -> "修改$input" } }.observe(this@MainActivity, { newName -> binding.data = newName.toString() }) // ====== Transformations.map 处理 类型转换 (lambda简化后) ====== Transformations.map(currentName) { input -> "修改$input" }.observe(this, { newName -> binding.data = newName })
-
Transformations.switchMap()
• 可以通过
Transformations
的switchMap()
操作符 通过room
做数据查询等// ====== Transformations.map 处理 类型转换 ====== val userLiveData = Transformations.switchMap(currentName, object : Function<String, LiveData<User>> { override fun apply(input: String?): LiveData<User> { // 根据 userId 返回一个 LiveData<User>,可通过 room 获取 return dao.getUser() } }) // ====== Transformations.map 处理 类型转换 (lambda简化后) ====== val userLiveDataL = Transformations.switchMap(currentName, Function<String, LiveData<User>> { // 根据 userId 返回一个 LiveData<User>,可通过 room 获取 dao.getUser() })
-
自定义
CustomTransformations
• 如有更复杂需求可通过MediatorLiveData
自定义transformations
•Transformations
源码就是通过MediatorLiveData
实现二次转发
• 里面其实主要用的就是MediatorLiveData
,通过该类能组合多个LiveData
源。当任何一个LiveData
源发生改变的时候,MediatorLiveData
的Observers
都会被触发。比如有两个LiveData
,一个是从数据库获取,一个是从网络获取。通过MediatorLiveData
就能做到,当二者任何一个获取到最新数据,就去触发监听。public class Transformations { private Transformations() { } @MainThread @NonNull public static <X, Y> LiveData<Y> map( @NonNull LiveData<X> source, @NonNull final Function<X, Y> mapFunction) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(source, new Observer<X>() { @Override public void onChanged(@Nullable X x) { result.setValue(mapFunction.apply(x)); } }); return result; } @MainThread @NonNull public static <X, Y> LiveData<Y> switchMap( @NonNull LiveData<X> source, @NonNull final Function<X, LiveData<Y>> switchMapFunction) { final MediatorLiveData<Y> result = new MediatorLiveData<>(); result.addSource(source, new Observer<X>() { LiveData<Y> mSource; @Override public void onChanged(@Nullable X x) { LiveData<Y> newLiveData = switchMapFunction.apply(x); if (mSource == newLiveData) { return; } if (mSource != null) { result.removeSource(mSource); } mSource = newLiveData; if (mSource != null) { result.addSource(mSource, new Observer<Y>() { @Override public void onChanged(@Nullable Y y) { result.setValue(y); } }); } } }); return result; } @MainThread @NonNull public static <X> LiveData<X> distinctUntilChanged(@NonNull LiveData<X> source) { final MediatorLiveData<X> outputLiveData = new MediatorLiveData<>(); outputLiveData.addSource(source, new Observer<X>() { boolean mFirstTime = true; @Override public void onChanged(X currentValue) { final X previousValue = outputLiveData.getValue(); if (mFirstTime || (previousValue == null && currentValue != null) || (previousValue != null && !previousValue.equals(currentValue))) { mFirstTime = false; outputLiveData.setValue(currentValue); } } }); return outputLiveData; } }
Demo地址 : LiveData[module]
2020年9月2日