Demo地址: Kotlin-Dagger-2-Retrofit-Android-Architecture-Components
在初探Architecture Components之Lifecycle中,我们已经了解到Lifecycle是如何与组件的生命周期相关联的。在本文中,我们将会了解Architecture Components库如何管理数据,那就是LiveData?LiveData是一个持有数据的类,并将数据作为其值,并允许监测它(用了观察者模式)。与常规的观察者模式不同,LiveData与组件的生命周期, 以便Observer在指定的生命周期内观察数值的变化。
不管LiveData是与组件的生命周期相关联,还是其采用观察者模式检测数值的变化,它有什么吸引力让我们使用它呢?
- 避免内存泄漏: 由于Observers绑定本身的Lifecycle对象, 当Lifecycle被销毁时, 其自动被移除。
- Activity处于onstop状态时, 不会导致应用程序意外崩溃: 当观察者的的生命周期处于非活动状态(比如Activity处于后台堆栈)时, Observer不会接到数据的变化
- 收到更改事件
- 始终保持最新的数据: 当Lifecycle再次回到可活动状态时(比如Activity从后台堆栈返回到前台), 它会受到最新的更改信息
- 适当的配置更改: 如果由于配置更改(比如设置旋转)重新创建Activity/Fragment时, 会立即接收到最有可用的数据。
- 共享资源: 可用保留一个有用的实例, 分享给多个Activity或者Fragment
- 没有针对生命周期做出多余的针对处理: 一切生命周期的变化, 所造成的的处理事务, 由LiveData自动管理。
这里有两个疑问,LiveData是如何始终保持最新的数据呢?如果在后台获取到数据,Observe是在什么时候接收到数据盘的呢?带着这两个疑问接着往下看…
在LiveData中,有4个重要的方法:
- onActive(): 当LiveData有可观察的对象时回调
- onInactive(): 当LiveData没有可观察的对象时回调
- setValue(): 当LiveData更新实例的值时调用, 并通知Observer数据的更改
- postValue: 当LiveData更新实例的值时调用, 并通知Observer数据的更改
其中,setValue和postValue方法都是用来LiveData更新实例时调用。值得注意的是,setValue方法只能在主线程中调用,而postValue可以在任何线程中调用。也就是说,如果是在后台子线程中更新LiveData的值,必须调用postValue。
class PersonActivity : LifecycleActivity(), LifecycleRegistryOwner {
***
override fun onCreate(savedInstanceState: Bundle?) {
***
Log.i("tea", " onCreate")
personLiveData.observe(this, Observer<Person?> {
Log.d("tea", "id: ${it?.id} | name: ${it?.name}")
tvValue.text = "id: ${it?.id} | name: ${it?.name}"
})
setListener()
}
private fun setListener() {
btnSet.setOnClickListener {
personLiveData.value = Person(1, "SetValue")
}
btnPost.setOnClickListener {
doAsync {
personLiveData.postValue(Person(1, "PostValue"))
}
}
}
override fun onStop() {
super.onStop()
personLiveData.value = Person(3, "onStop")
Log.i("tea", " onStop")
}
}
class PersonLiveData : LiveData<Person>() {
override fun onActive() {
super.onActive()
Log.d("tea", "onActive")
}
override fun onInactive() {
super.onInactive()
Log.d("tea", "onInactive")
}
public override fun postValue(value: Person?) {
super.postValue(value)
}
public override fun setValue(value: Person?) {
super.setValue(value)
}
}
由于LiveData是一个抽象类,无法创建创建实例。现创建LiveData的子类PersonLiveData,PersonActivity中创建了PersonLiveData实例。值得注意的是, observe()方法的第一个参数为LifecycleOwner, 表示Observer应当绑定Lifecycle, 这样意味着:
- Lifecycle未处于STARTED或RESUMED状态, 即使该值发生了变化, Observer不会被通知。
- 如果Lifecycle被杀掉, Observer将被自动清除。
在onStop方法里我们通过setValue方法更改了personLiveData中数据的值,我们来看看Observer是什么时候接收到的数值变化的通知呢?
从下图中,我们可以清晰的看到:Observe并没有在personLiveData中数据值发生变化时立即受到通知,而是在PersonActivity重新可见时,Observe才接收到数值变化的通知。关于这样的优点,这里不必多说,前面已有介绍。
在下图中,我们可以还可以看到组件的生命周期、LiveData和Lifecycle等相关方法的调用顺序:
LiveData与组件的生命周期相关联, 意味着我们可以在多个Activity或者Fragment中共用它。 前面我们是在Activity中使用它,我们一样在Fragment中使用:
public class MyFragment: LifecycleFragment() {
fun onActivityCreated (Bundle savedInstanceState) {
personLiveData.observe(this, Observer<Person?> {
Log.d("tea", "id: ${it?.id} | name: ${it?.name}")
tvValue.text = "id: ${it?.id} | name: ${it?.name}"
})
}
}
LiveData的转换
有时候,在将数据变化信息发送给Observer之前,需要对LiveData值的数据类型进行更改(这里说的不是值本身的变化,而是数据类型的变化),此时,就需要需要依据当前LiveData,返回另外一个LiveData实例。我们该怎么做呢?是在Observe回调里面重新创建一个LiveData还是?
在android.arch.lifecycle包提供了Transformations工具类, 用于LieveData值的数据类型的更改。在Transformations类中有两个方法map()和switchMap.
map
先看map方法,它接受两个参数:一个LiveData作为数据源和一个转换函数Function。其中,传递的转换函数应在主线程中执行,因为该函数用于数据源LiveData发出的每个值,并返回发出结果值的LiveData。
现在我们将personLiveData的值的数据类型转换String类型:
var personMapLiveData: LiveData<String>
personMapLiveData = Transformations.map(personLiveData, {
it: Person? ->
it?.name
})
personMapLiveData.observe(this, Observer<String> {
tvMap.text = it
})
switchMap
现在我们看看switchMap,与map类似,将LiveData的值更改信息传递给子LiveData,不同的是,传递给它的函数必须返回一个LiveData对象。这就意味着,这种实现可能从将原来的LiveData销毁,并且在数据源LiveData数值发生变化时,重新创建一个新的LiveData实例。
var personSwitchMapLiveData: LiveData<String>
personSwitchMapLiveData = Transformations.switchMap(personLiveData) {
val result = MediatorLiveData<String>()
it.name
result.postValue(it.name)
result
}
personSwitchMapLiveData.observe(this, Observer<String> {
tvSwitchMap.text = it
})
自定义LiveData
前面提到了LiveData的重要方法中包括setValue和postValue,值得注意的是这两个方法使用protected修饰,这意味着它们只能在LiveData的子类中调用。又由于,LiveData是一个抽象类,我们并不能创建其相应的实例。如果我们想创建其实例,不得不自定义LiveData的子类,比如,前面定义的PersonLiveData。在android.arch.lifecycle包中,有LiveData的两个实现类:MutableLiveData和MediatorLiveData。
MutableLiveData继承自LiveData,其主要是对外公布了setValue和postValue(注意方法的调用时所属线程)。
public class MutableLiveData<T> extends LiveData<T> {
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
而,MediatorLiveData又继承自MutableLiveData类,也就是说该类也公开了setValue和postValue方法。该类该又增加了监测其他LiveData实例值个更改并处理它们发出的事件。
- addSource(LiveData<S> source, Observer<S> onChanged):添加监控的LiveData实例值及LiveData的值变化时处理的Observe
- removeSource(LiveData<S> toRemote):移除监控的LiveData实例值
如果你兴趣可以根据自己的需求自定义LiveData,比如前面的PersonLiveData。