前言
从事Android开发两年有余了,从15年开始学习Android,到17年开始实际接触企业级Android APP的开发,这一路也从MVC走到了MVP。19年辞职后,休息期间研究了一下最新的Android Jetpack,萌生了一个大胆的想法——计划使用当前各类成熟的框架和技术如组件化、插件化、MVVM等等,结合AAC开发出一个自己之前从未走过的Android开发之路。
本篇文章是LiveData的初探,会用尽可能简洁的方式来了解LiveData,让我们对LiveData有一个初步印象,不会长篇大论或者源码轰炸,导致干货太多引起阅读困难。
目录
- LiveData生命周期与简介
- LiveData的使用
- LiveDataAPI介绍
- LiveData的扩展
- LiveData数据转换
正文
LiveData简介
LiveData的官方文档是这样介绍它的,
LiveData是一种具有生命周期感知能力的可观察数据持有类。
从它介绍中我们可以知道,LiveData是一个持有数据的类,同时可以感知Activity或Fragment的生命周期,并且支持观察者模式。
LiveData的使用
根据官方的介绍,可以按照以下的步骤来使用LiveData
1.创建一个LiveData的实例来保存特定类型的数据。 一般会把LiveData的实例定义在ViewModel类中。
val name: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
MutableLiveData是LiveData的一个子类,LiveData是一个抽象类,实例化LiveData需要使用MutableLiveData。
2.创建一个定义了onChanged()方法的Observer对象,当LiveData对象保存的数据发生变化时,onChanged()方法可以进行相应的处理。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//创建viewmodel
mViewModel = ViewModelProviders.of(this).get(LiveDataViewModel::class.java)
//声明观察TextView对象,
mViewModel.name.observe(this, Observer {
//实现onChanged()方法,这里使用了lambda表达式,省略了onChanaged()
textview.text = it
})
}
通常在UI控制器(如Activity或Fragment)中创建Observer对象。
3.调用LiveData的observe()方法需要传入两个参数,第一个参数LifecycleOwner对象,LifecycleOwner是一个接口,只要UI控制器实现了该接口,可以直接传this,Android中的Fragment和AppCompatActivity的父类都已经实现LifecycleOwner接口。第二个参数是Observer观察者,属于方法回调。
更新LiveData数据
MutableLiveData提供了两个更新数据的方法
- postValue(value: T)
- setValue(value: T)
两个方法都可以用来更新LiveData中数据,区别在与postValue可以在子线程中更新LiveData的数据,而setValue只能在UI线程中更新LiveData的数据。
注意: UI控制器(activity和fragment)只应该负责显示数据,不应该保存任何数据,所以不要在UI控制器中创建LiveData的实例。
LiveDataAPI介绍
getValue():T
返回LiveData当前的存储的值
hasActiveObservers():Boolean
如果当前的LiveData存在活跃的Observer对象,则返回true
hasObservers():Boolean
如果当前的LiveData存在Observer对象,则返回true
observe(@NonNull owner: LifecycleOwner, @NonNull observer: Observer)
将给定的观察者添加到给定所有者的生命周期内的观察者列表中。
observeForever(@NonNull observer: Observer)
注册一个没有关联LifecycleOwner对象的Observer。 在这种情况下,Observer被认为始终处于活动状态,因此当有数据变化时总是会被通知。 可以调用removeObserver(Observer)方法移除这些Observer。
removeObserver(@NonNull observer: Observer)
从观察者列表中删除给定的观察者。
removeObservers(@NonNull owner: LifecycleOwner)
删除与给定关联的所有观察者LifecycleOwner。
LiveData的扩展
LiveData的扩展千变万化,这里只介绍LiveData的源码中预留的两个空实现方法的扩展
- onActive()
当LiveData对象有一个活跃的Observer时,onActive()方法被调用。
- onInactive()
当LiveData对象没有任何活跃的Observer时,onInactive()方法被调用。
通过onActive和onInactive方法我们可以很轻松的知道当前LiveData对象是否有正在活跃的观察者对象,并根据业务逻辑作出合适的调整。
LiveData对象具有感知生命周期的能力意味着可以在多个Activity,Fragment和service之间共享它们。 为了保持简洁,可以使用单例模式实现LiveData
class ExpandLiveData :LiveData<String>() {
companion object {
private lateinit var sInstance: ExpandLiveData
@MainThread
fun get(): ExpandLiveData {
sInstance = if (::sInstance.isInitialized) sInstance else ExpandLiveData()
return sInstance
}
}
//当活动的观察者数量从0变为1时调用。
override fun onActive() {
super.onActive()
}
//当活动的观察者数量从1变为0时调用。
override fun onInactive() {
super.onInactive()
}
}
在activity中就可以用如下的方式调用
ExpandLiveData.get().observe(this, Observer {
//doSomething
})
LiveData的数据转换
通过上述的介绍,我们对LiveData有了一个初步的印象,LiveData是一个可以感知生命周期的的数据持有类,同时支持观察者模式。说到观察者模式,我们一定会联想到Rxjava,Rxjava中提供了多种多样的操作符,极大的便利了Android开发。LiveData的开发者们同样也给LiveData带来了与Rxjava类似的多种操作符。
与Rxjava不同的是,在LiveData中需要借助Transformations类来完成LiveData的数据转换
- map(liveData,function)
map操作符,与rxjava的map操作符语义非常相似,可修改LiveData的输出值。map方法有两个参数,第一个参数是需要转换的LiveData源,第二个参数是自定义的转换方法。示例如下:
val newLiveData = Transformations.map(ExpandLiveData.get()) { string ->
//把转换前的livedata的value加了一个new
"new$string"
}
newLiveData.observe(this, Observer { string ->
Log.e("newLiveData", string)
})
ExpandLiveData.get().observe(this, Observer { string ->
Log.e("ExpandLiveData", string);
})
输出结果:
E/newLiveData: newExpand
E/ExpandLiveData: Expand
- switchMap
switchMap与map相似,区别在于:map给出的是具体的值,而switchMap给出的是具体的LiveData。
举个例子:有这样一个方法getUser(Id),通过传入用户的Id,来查找用户的具体信息,并返回一个LiveData<User>对象。当界面传入的用户Id发生变化时,需要根据Id重新查找用户的LiveData,这时就需要解除上一个LiveData关联界面UI信息,绑定新的UI消息。如果我们使用switchMap,就可以避免重复的解绑和绑定操作。示例如下:
//模拟查找用户的操作,这里重新生成了一个UserLiveData
fun getUser(id: String): MutableLiveData<String> {
//返回查到的UserLiveData,value是固定link加上用户的Id,例如:userId=1000,返回值就是link-1000
val userLiveData=MutableLiveData<String>()
userLiveData.value="link-${id}"
return userLiveData
}
//用一个按钮来模拟修改UserId
button.setOnClickListener {
//通过随机数动态修改userId
userIdLiveData.value = Random.nextInt(0, 10000).toString()
}
//通过switchMap动态返回不同Id的UserLiveData
val userIdLiveData = MutableLiveData<String>()
Transformations.switchMap(userIdLiveData) { userId ->
Log.e("switchMap", userId)
getUser(userId)
}.observe(this, Observer {
//输出当前getUser()中返回的UserLiveData的值
Log.e("userLiveData", it)
})
输出结果:
E/switchMap: 9320
E/userLiveData: link-9320
E/switchMap: 7116
E/userLiveData: link-7116
通过上面例子我们可以看到,不管需要查找多少个用户的LiveData,界面都只需要观察生成的LiveData一次即可。
- MediatorLiveData
如果map和switchMap都不能满足你对数据格式转换的需求,那么还可以使用MediatorLiveData进行自定义的数据转换。
MediatorLiveData是LiveData的一个子类,它可以添加或者移除多个源LiveData对象,将多个源LiveData对象组合一个单一的LiveData对象。任何LiveData源对象发生改变后,MediatorLiveData的Observer都会被触发。
上面的map和switchMap的底层实现实际上也是使用了MediatorLiveData,我们可以简单看一下map的源码,来对MediatorLiveData的使用又一个大致的了解。
@MainThread
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;
}
MediatorLiveData的使用暂时先不介绍,我们只需要对它有个大致的了解,具体的细节,会在后续的文章中介绍。
总结
本篇文章的简要介绍了LiveData是什么,以及如何使用LiveData。其实只要记住LiveData本质上就是一个可以感知生命周期的数据持有类,支持观察者模式,就可以了,其他的细节几乎都是对其特性的扩展。当我们记牢LiveData的特性后,或许就不会在开发中产生“我为毛要使用LiveData”的疑问了。
在AAC架构中LiveData和ViewModel占据了很重要的位置,下一篇我们再来介绍ViewModel。