完全掌握LivaData

349 阅读4分钟

一、LiveData简介

1、LivaData是什么?

LiveData 是一种具有生命周期(如 Activity、Fragment 或 Service)感知能力的、可观察的数据存储器类。LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

image.png

2、LivaData的优势

2-1:LiveData能确保UI和数据状态相符

LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知 Observer 对象来更新界面。

2-2:不会发生内存泄漏

观察者和Lifecycle对象绑定,能在销毁时自动解除注册

2-3:不会给已经停止的Activity发送事件

如果观察者处于非活跃状态,LiveData不会再发送任何事件给这些Observer对象

2-4:不再需要手动处理生命周期

UI组件仅仅需要对相关数据进行观察,LiveData自动处理生命周期状态改变后,需要处理的代码。

2-5:数据始终保持最新状态

一个非活跃的组件进入到活跃状态后,会立即获取到最新的数据,不用担心数据问题

2-6:LiveData在横竖屏切换等Configuration改变时,也能保证获取到最新数据

例如Acitivty、Fragment因为屏幕选装导致重建, 能立即接收到最新的数据

2-7:LiveData能资源共享

如果将LiveData对象扩zhan,用单例模式将系统服务进行包裹。这些服务就可以在app中共享。

3、LiveData的劣势

3-1:LiveData只能在主线程转换更新数据

postValue也是需要切换到到主线程的,当我们想要更新LiveData对象时,我们会经常更改线程(工作线程→主线程),如果在修改LiveData后又要切换回到工作线程那就更麻烦了

3-2:postValue可能会有丢数据的问题

在一段时间内发送数据的速度 > 接受数据的速度,可能导致数据丢失,LiveData 无法正确的处理这些请求。

3-3:LiveData结构简单就是有意被简化设计,LiveData的操作符也不够强大

面对比较复杂的交互数据流场景时,处理起来比较麻烦。

二、LiveData的使用

MutableLiveData的使用

  • 1、在ViewModel中创建一个实例LiveData来保存某种类型的数据。
class NameViewModel : ViewModel() {

    // 创建一个字符串类型的LiveData
    val currentNameLiveData: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

    // Rest of the ViewModel...
}
  • 2、注册观察者Observer并实现onChanged方法,该方法在LiveData对象持有的数据变化的时候回调,来更新UI
class NameActivity : AppCompatActivity() {

    // Use the 'by viewModels()' Kotlin property delegate
    // from the activity-ktx artifact
    private val model: NameViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Other code to setup the activity...
        
        // 为LiveData注册Observer观察者
        model.currentNameLiveData.observe(this, object : Observer<String>{
            override fun onChanged(newName: String?) {
                // Update the UI,
                nameTextView.text = newName
            }
        })
    }
}
  • 3、更新LiveData对象
button.setOnClickListener {
    val anotherName = "Hello"
    model.currentNameLiveData.setValue(anotherName)
}

注意点,LiveData建议封装在ViewModel内部使用:

  • 避免造成Activity和Fragment的臃肿。现在这些 UI 控制器负责显示数据但不保存数据状态。
  • LiveData实例与特定Activity和Fragment实例分离,从而确保LiveData对象在横竖屏切换后继续存在。

LiveData的数据转换

  • 1、Transformations.map map函数:基于原LiveData,对其值进行改变然后生成一个新的LiveData返回

api:

/**
 * @param  source:用于转换的LiveData原始对象
 * @param  mapFunction: 转换函数
 */
public static LiveData<Y> map (LiveData<X> source, Function<X, Y> mapFunction)

示例:

data class User(val firstName:String,val lastName:String){}

val userLiveData: MutableLiveData<User> by lazy{
    MutableLiveData<User>(User("三","张"))
}

// 传入MutableLiveData<User>(User("三","张")) -> MutableLiveData<String>(”张三“)
val userName: MutableLiveData<String> = Transformations.map(userLiveData) {
    user -> "${user.lastName} ${user.firstName}"
}

Transform.png.png

  • 2、Transformations.switchMap() switchMap()函数: 传入LiveData对象,当此LivaData中值变化时,调用转换函数生成新的LiveData对象返回。

api:

/**
 * @param  source:传入待观察的LiveData对象
 * @param  switchMapFunction: 转换函数
 */
public static LiveData<Y> switchMap (LiveData<X> source, Function<X,LiveData<Y>> switchMapFunction)

示例:

// 条件结果liveDataA
val liveDataA = MutableLiveData<String>("1001")
// 条件结果liveDataB
val liveDataB = MutableLiveData<String>("2002")
// 条件LiveData
val liveDataSwitch = MutableLiveData<Boolean>(false)

// Transformations.switchMap 监测liveDataSwitch值的变化,条件触发不同的liveData返回
val transformSwitchedLiveData =
    Transformations.switchMap(liveDataSwitch) {
    switchToB ->
        if(switchToB) { liveDataB }
        else{ liveDataA }
    }

// 注册监听
transformSwitchedLiveData.observe(this,Observer<String> { value ->
    value?.let {
        txt_fragment.text = it
    }
})

// SwitchCompat 开关手动控制liveDataSwitch值的变化
liveDataSwitch.value = switch_live_data.isChecked
switch_live_data.setOnCheckedChangeListener { buttonView, isChecked ->
    liveDataSwitch.value = isChecked
}

switchMap.png.png

MediatorLiveData的使用

  • MediatorLiveData可以作为中介观察或调度多个 LiveData 数据源
  • 同时也可以做为一个liveData,被其他Observer观察

示例

  • 监听多个不同类型数据源,map()switchMap()也应用了MediatorLiveData中介功能
    // String 类型的liveData
    private val liveData1 = MutableLiveData<String>()
    // Int类型的liveData
    private val liveData2 = MutableLiveData<Int>()
    
    fun setData1(name: String) {
        liveData1.value = name
    }
    fun setData2(id: Int) {
        liveData2.value = id
    }
  
    val mediatorLiveData = MediatorLiveData<String>()
    init {
        mediatorLiveData.addSource(liveData1) {   
           mediatorLiveData.value = "A:$it"
        }
        mediatorLiveData.addSource(liveData2) {
           mediatorLiveData.value = "B:$it"
        }
    }
    // 监听不同数据源更新UI
    mediatorLiveData.observe(this, changeObserver)
    private val changeObserver = Observer<String> { value ->
        value?.let {
            text = it
        }
    }

image.png

使用多个MutableLiveData 单独观察数据,更新UI也能实现以上功能,但MutableLiveData需要分别要设置 LifecycleOwnerMediatorLiveData 能统一管理添加到它内部所有 LiveData 的生命周期, MediatorLiveData 重写了 LiveDataonActiveonInactive 方法统一去添加和移除它内部 LiveData 的 Observer

可用点

  • MediatorLiveData监听不同来源(缓存、内置、网络)LiveData,更新UI数据