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强化实战