Android Jetpack架构组件——LiveData使用篇

Posted 我就是马云飞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack架构组件——LiveData使用篇相关的知识,希望对你有一定的参考价值。

概述

一般来说,LiveData很少单独使用,它更多的和android Jetpack的其他组件搭配使用,比如ViewModel和ViewBinding。所以前面我们介绍ViewModel的使用以及其实现原理。那么这篇文章就来介绍LiveData的使用。

LiveData是什么?

通过字面意思其实我们可以理解成生存(活着)的数据。我们看下官方是怎么介绍它的:

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

化繁为简:

  • LiveData具备生命周期的感知能力
  • LiveData只存在活跃的生命周期里,比如STARTED或RESUMED。

LiveData的优势

使用 LiveData 具有以下优势:

  • 确保界面符合数据状态
    LiveData 遵循观察者模式。当底层数据发生变化时,LiveData会通知Observer对象。您可以整合代码以在这些Observer对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。

  • 不会发生内存泄漏
    观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。
    不会因 Activity 停止而导致崩溃如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何LiveData事件。

  • 不再需要手动处理生命周期
    界面组件只是观察相关数据,不会停止或恢复观察。LiveData将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。

  • 数据始终保持最新状态
    如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的Activity会在返回前台后立即接收最新的数据。

  • 适当的配置更改
    如果由于配置更改(如设备旋转)而重新创建了Activity或Fragment,它会立即接收最新的可用数据。

  • 共享资源
    您可以使用单例模式扩展LiveData对象以封装系统服务,以便在应用中共享它们。LiveData对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察LiveData对象。

如何使用LiveData

前面我们介绍了LiveData是什么以及它的优势有什么,那么接下来我们介绍下到底如何使用它。

基本使用

LiveData是一个抽象类,不能直接使用,我们一般使用它的直接子类MutableLiveData。那我们直接写例子,直接在之前的ViewModel里面修改代码:

/**
 * @date:2021/2/22
 * @author:Silence
 * @describe:
 **/
class MyViewModel : ViewModel() 

    var userData: MutableLiveData<UserInfo> = MutableLiveData()

    fun getUserInfo() 
        val user = UserInfo("我就是马云飞", (1..100).random())
        userData.postValue(user)
    

    fun updateUserInfo(userInfo: UserInfo) 
        userData.postValue(userInfo)
    

然后我们看看怎么在Activity里面获取这个data呢。接着看代码:

    private val viewModel by lazy  ViewModelProvider(this).get(MyViewModel::class.java) 
    private var count = 0
    
    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_view_model)
        viewModel.userData.observe(this, Observer 
            Log.i(TAG, "onCreate: " + "姓名:$it.name \\t年龄:$it.age")
        )
        liveDataBtn.setOnClickListener 
            if (count % 2 == 0) 
                viewModel.getUserInfo()
             else 
                val user = UserInfo("你不是马云飞", (1..100).random())
                viewModel.updateUserInfo(user)
            
            count++
        
    

我们在Activity中对viewModel的userData做了监听,实时观察数据的变化。那么我们现在进行点击看看效果如何:

果然,只要我数据更新了,我的Log立马就输出了。

扩展使用

如果观察者的生命周期处于STARTED或RESUMED状态,则LiveData会认为该观察者处于活跃状态。我们直接看官方的例子:

class StockLiveData(symbol: String) : LiveData<BigDecimal>() 
    //股票管理类
    private val stockManager: StockManager = StockManager(symbol)

    //监听股票价格的变化
    private val listener =  price: BigDecimal ->
        //更新value值
        value = price
    

    //页面处于活跃状态时,开始观察股票价格的数据更新
    override fun onActive() 
        stockManager.requestPriceUpdates(listener)
    

    //页面处于非活跃状态,移除相关监听
    override fun onInactive() 
        stockManager.removeUpdates(listener)
    

    companion object 
        private lateinit var sInstance: StockLiveData

        //这是一个单例
        @MainThread
        fun get(symbol: String): StockLiveData 
            sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
            return sInstance
        
    


//Fragment中的使用
class MyFragment : Fragment() 

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) 
        super.onViewCreated(view, savedInstanceState)
        StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal>  price: BigDecimal? ->
            // Update the UI.
        )

    

我们看下上述的代码,具体包含如下功能:

  • 本身是个单例,也就是可以在多个Activity与Fragment中进行数据监听。

  • 当具备活跃的观察者时,会调用onActive方法,监听股价的变动。

  • 当其观察者不具备活跃状态时,会调用onInactive方法,移除监听。也就是就算值改变了,也不会同步更新,同理,当页面销毁时,会自动移除监听。

数据转换

map

我们按照上面我们的示例代码继续,前面我们打印了姓名和年龄,那么假设,我暂时不需要字段,我需要通过姓名拿到他的班级以及学号。也就是通过姓名将数据转换成班级和学号,LiveData也给我们提供了相关方法,可以通过Transformations.map去实现。具体代码如下:

// ViewModelActivity.kt
override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_view_model)
        viewModel.userData.observe(this, Observer 
            Log.i(TAG, "onCreate: " + "姓名:$it.name \\t年龄:$it.age")
        )
        viewModel.getUserInfo()
        viewModel.classInfo.observe(this, Observer 
            Log.i(TAG, "onCreate: " + "班级:$it?.grade \\t学号:$it?.id")
        )
        liveDataBtn.setOnClickListener 
            viewModel.getClassIdByUser().observe(this, Observer 
            )
        
    

// MyViewModel.kt
fun getClassIdByUser(): LiveData<ClassBean?> 
        return Transformations.map(userData)  input ->
            var classBean: ClassBean? = null
            if (input?.name == "我就是马云飞") 
                classBean = ClassBean("高三", (1..100).random())
                classInfo.postValue(classBean)
            
            classBean
        
    

首先我们进入页面先获取一次用户的姓名和年龄,然后当我们点击按钮的时候,我们根据用户的姓名给他定义一个班级和学号。我们来看下效果:

可以看到,每次点击的时候,它都会给我们生成一个学号。说明我们的数据转换成功了。

switchMap

switchMap的方法和map大同小异,只是它是返回一个liveData,而上面map是直接返回T。我们直接上代码:

 fun getClassIdByUser(): LiveData<ClassBean?> 
        return Transformations.switchMap(userData) 
            val classBean = ClassBean("高三", (1..100).random())
            classInfo.postValue(classBean)
            classInfo
        
    

输出也基本差不多。

数据合并

所谓的数据合并是什么呢?之前我们如果有多套的LiveData,我们需要对多套数据进行观察。而数据合并可以做到批量添加LiveData并且只实现一组观察逻辑就可以监听多套数据的改动。我们修改一下代码:

        viewModel.mediatorLiveData.addSource(viewModel.userData) 
            Log.i(TAG, "卧槽,数据合并也可以监听!!!!onCreate: " + "姓名:$it.name \\t年龄:$it.age")
        
        viewModel.mediatorLiveData.addSource(viewModel.classInfo) 
            Log.i(TAG, "卧槽,数据合并也可以监听!!!!onCreate: " + "班级:$it?.grade \\t学号:$it?.id")
        
        viewModel.mediatorLiveData.observe(this, Observer<Any?> 
        )
        liveDataBtn.setOnClickListener 
            if (count % 2 == 0) 
                viewModel.getUserInfo()
             else 
                viewModel.getClassInfo()
            
            count++
        

我们继续通过点击看看效果如何:

哎。可以了~

总结

本文我们主要介绍了LiveData是什么,以及它的优势和使用方法。而LiveData的很多细节我们没有去关注,比如postValue和setValue。比如Transformations的map和switchMap方法。后面我们会在LiveData原理篇讲到。毕竟我们需要了解它是怎么使用的。会使用后才会想去了解其原理。

参考

官网

本文首发于我的个人博客:Android Jetpack架构组件——LiveData使用篇

更多文章请关注我的公众号:码农职场

以上是关于Android Jetpack架构组件——LiveData使用篇的主要内容,如果未能解决你的问题,请参考以下文章

Android Jetpack架构组件——什么是Jetpack?

Android Jetpack架构组件——什么是Jetpack?

Android高级Jetpack架构组件+Jetpack compose强化实战

Jetpack之LiveData分析

Android Jetpack架构组件带你了解Android Jetpack

Android Jetpack架构组件(入门教程及进阶实战)独家首发