Android Jetpack架构组件-LiveData使用
谷歌推出的LiveData和RxJava类似,也是基于观察者,你可以认为LiveData是轻量级的RxJava。起初LiveData并不被看好,随着谷歌的大力推广,LiveData也慢慢的进入了大家的视野。一般来说,LiveData很少单独使用,它更多的和Android
Jetpack的其他组件搭配使用,比如和ViewModel、Room、Paging等。这篇文章就来介绍LiveData的使用。
一、定义
LiveData
是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
二、优势:
使用 LiveData 具有以下优势:
-
确保界面符合数据状态
LiveData 遵循观察者模式。当生命周期状态发生变化时,LiveData 会通知
Observer
对象。您可以整合代码以在这些Observer
对象中更新界面。观察者可以在每次发生更改时更新界面,而不是在每次应用数据发生更改时更新界面。 -
不会发生内存泄露
观察者会绑定到
Lifecycle
对象,并在其关联的生命周期遭到销毁后进行自我清理。 -
不会因 Activity 停止而导致崩溃
如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
-
不再需要手动处理生命周期
界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
-
数据始终保持最新状态
如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。
-
适当的配置更改
如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
-
共享资源
您可以使用单一实例模式扩展
LiveData
对象以封装系统服务,以便在应用中共享它们。LiveData
对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察LiveData
对象,后文都会提高
三、使用liveData
LiveData的数据源一般是ViewModel,也可以是其它可以更新LiveData的组件。当数据更新后,LiveData 就会通知它的所有观察者,比如Activiy。
与RxJava的方法不同的是,LiveData并不是通知所有观察者,它只会通知处于Active状态的观察者,如果一个观察者处于Paused或Destroyed状态,它将不会收到通知。
这对于Activiy和Service特别有用,因为它们可以安全地观察LiveData对象而不用担心内存泄漏的问题。开发者也不需要在onPause或onDestroy方法中解除对LiveData的订阅。还有一点需要注意的是一旦观察者重新恢复Resumed状态,它将会重新收到LiveData的最新数据。
3.1、 LiveData的基本使用
示例为Button事件点击,LiveData发送个数据,观察者接收到数据更新以后更新UI
class LiveDataActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_live_data)
var liveData: LiveData<String> = MutableLiveData<String>()
btn_ald_post.setOnClickListener {
//发送数据
(liveData as MutableLiveData).postValue("有新消息了")
}
//观察livedata对象
liveData.observe(this, Observer<String> {
//Updata UI
tv_ald_info.text = it
})
}
}
liveData.observe(this,Observer<String>)方法有两个参数分别是LifecycleOwner
和 Observer
,第一个参数就是LiveDataActivity本身,因为父类已实现了LifecycleOwner接口,详情可参考笔者Lifecycle的文章,第二个参数则新建了一个Observer
,在onChanged方法中得到回调。注释处的postValue方法会在主线程中更新数据,这样就会更改TextView中text属性的值。
在大多数情况下,LiveData的observe方法会放在onCreate方法中,如果放在onResume方法中,会出现多次调用的问题。除了MutableLiveData的postValue方法,还可以使用setValue方法,它们之前的区别是,setValue方法必须在主线程使用,如果是在工作线程中更新LiveData,则可以使用postValue方法。
3.2、 更改LiveData中的数据
如果我们想要在LiveData对象分发给观察者之前对其中存储的值进行更改,可以使用Transformations.map()
和Transformations.switchMap()
,类似于Rxjava中的map()方法
下面通过简单的例子来讲解它们
var liveData: LiveData<String> = MutableLiveData<String>()
btn_ald_post.setOnClickListener {
(liveData as MutableLiveData).postValue("有新消息了")
}
var changLiveData = Transformations.map(liveData) {
it + "changed"
}
changLiveData.observe(this, Observer<String> {
tv_ald_info.text = it
})
运行结果为TextView的值为
"有新消息changed"
3.3、 Transformations.switchMap()
如果想要手动控制监听其中一个的数据变化,并能根据需要随时切换监听,这时可以使用Transformations.switchMap(),它和Transformations.map()使用方式类似,只不过switchMap()必须返回一个LiveData对象。
MediatorLiveData
是 LiveData
的子类,允许您合并多个 LiveData 源。只要任何原始的 LiveData 源对象发生更改,就会触发 MediatorLiveData
对象的观察者。
例如,如果界面中有可以从本地数据库或网络更新的 LiveData
对象,则可以向 MediatorLiveData
对象添加以下源:
- 与存储在数据库中的数据关联的
LiveData
对象。 - 与从网络访问的数据关联的
LiveData
对象。
�
代码如下所示:
class MergerLiveDataActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_merger)
val mutableLiveData1 = MutableLiveData<String>()
val mutableLiveData2 = MutableLiveData<String>()
val mutableLiveData3 = MutableLiveData<String>()
val liveDataMerger: MediatorLiveData<*> = MediatorLiveData<String>()
liveDataMerger.addSource(mutableLiveData1, object : Observer<String> {
override fun onChanged(t: String?) {
Log.d("TAG", "onChanged1:$t")
}
})
liveDataMerger.addSource(mutableLiveData2, object : Observer<String> {
override fun onChanged(t: String?) {
Log.d("TAG", "onChanged2:$t")
}
})
liveDataMerger.addSource(mutableLiveData3, object : Observer<String> {
override fun onChanged(t: String?) {
Log.d("TAG", "onChanged3:$t")
}
})
liveDataMerger.observe(this, Observer {
Log.d("TAG", "onChanged:$it");
})
mutableLiveData1.postValue("Onexzgj 的Jetpack")
mutableLiveData2.postValue("Onexzgj 的Jetpack2")
mutableLiveData3.postValue("Onexzgj 的Jetpack3")
}
}
为了更直观的举例,将LiveData和MediatorLiveData放到了同一个Activity中。通过MediatorLiveData的addSource将两个MutableLiveData合并到一起,这样当任何一个MutableLiveData数据发生变化时,MediatorLiveData都可以感知到。
打印结果如下,任何一个liveData发生变化,liveDataMerger都会接受到通知
截屏2020-03-2512.10.32.png3.4、扩展LiveData对象
如果观察者的生命周期出于STARTED或者RESUMED状态,LiveData会将观察者视为处于Active状态,关于如何扩展LiveData,官网的例子比较简洁,如下所示:
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
private val stockManager = StockManager(symbol)
private val listener = { price: BigDecimal ->
value = price
}
override fun onActive() {
stockManager.requestPriceUpdates(listener)
}
override fun onInactive() {
stockManager.removeUpdates(listener)
}
}
上面的代码是一个观察股票变动的一个例子,对LiveData进行了拓展,实现了LiveData的两个空方法onActive和onInactive。当Active状态的观察者的数量从0变为1时会调用onActive方法,通俗来讲,就是当LiveData对象具有Active状态的观察者时调用onActive方法,应该在onActive方法中开始观察股票价格的更新。当LiveData对象没有任何Active状态的观察者时调用onInactive方法,在这个方法中,断开与StockManager服务的连接。
LiveData
对象具有生命周期感知能力,这一事实意味着您可以在多个 Activity、Fragment 和 Service 之间共享它们。为使示例保持简单,所以可以将 LiveData
类实现为单一实例,如下所示:
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
private val stockManager: StockManager = StockManager(symbol)
private val listener = { price: BigDecimal ->
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 onActivityCreated(savedInstanceState: Bundle?) {
StockLiveData.get(symbol).observe(this, Observer<BigDecimal> { price: BigDecimal? ->
// Update the UI.
})
}
多个 Fragment 和 Activity 可以观察 MyPriceListener
实例。仅当一个或多个系统服务可见且处于活跃状态时,LiveData 才会连接到该服务。
四、总结
这篇文章主要介绍了什么是LiveData,简而言之可以理解为RxBus,以及LiveData的使用方法,这里没有介绍LiveData
和ViewModel
的结合使用,以及LiveData的原理,这些会在后面的文章进行介绍。
最后文章中涉及到的源码及Jetpack的全组件均上传至OnexZgj/Jetpack_Component