前面一篇博客中讲到了Lifecycle。而这篇博客中要将的LiveData其底层也是用Lifecyle来进行实现的。而且个人它是一个用来代替DataBinding中我们没有讲到的Observerxxx系列类的,但是官方有说在某些情况还是不能代替,我暂时没有发现Observable能做的事情LiveData不能做,感兴趣的可以去官方文档去看。因为相比于Observerxxx类有一系列的优点。其中主要就是它借助于Lifecycle具有生命周期感知。
通常我们称STARTED、RESUMED状态为active状态,反之处于inactiv状态。如果监视LiveData的Observer处于active状态,那么LiveData的变化就会通知Observer,反正就不会通知,但是这个更新会在Observer一处于active状态就通知它。
依赖添加
通常我们使用LiveData与后面要讲的ViewModel进行一起的使用。因为ViewModel具有一些很方便的特性。比如说,让Fragment之间的通信轻而易举等;还有就是如果屏幕配置发生了变化,想横竖屏切换,这个时候在ViewModel中的值会保持不变。那么这篇博客给的例子我们就顺带的使用上ViewModel吧!
dependencies {
...
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0-beta01"
}
这里我们引用的这个依赖中包含了ViewModel和LiveData。如何想只引入LiveData或ViewModel就将extensions改为对应的名字就行。
使用LiveData
下面我们从一个例子中来看看LiveData的基本使用:
其中xml代码简单就是一个Button和TextView就不列了。
ViewModel类的实现
class NameViewModel: ViewModel() {
var mCurrentName: MutableLiveData? = null
get() {
if (field == null){
field = MutableLiveData()
}
return field
}
var index: Int = 0
}
这里我们让mCurrentName属性为MutableLiveData。这是一个LiveData的子类。
观察LiveData的变化
class MainActivity : AppCompatActivity() {
private lateinit var mNameViewModel: NameViewModel
override fun onCreate(savedInstanceState: Bundle?) {
...
//一
mNameViewModel = ViewModelProviders.of(this).get(NameViewModel::class.java)
//二
val observer = Observer {
tv.text = it
}
mNameViewModel.mCurrentName?.observe(this, observer)
//三
bt.setOnClickListener{
mNameViewModel.mCurrentName?.value = "anriku${mNameViewModel.index}"
mNameViewModel.index++
}
}
}
看到上面,我们有三个部分
第一部分,这是我们ViewModel的类实例化。在后面将ViewModel还会具体进行讲解。
第二部分,先实例化了一个Observer接口的匿名实现类。这个接口只有一个onChanged方法。再让我们的LiveData属性观察Observer的变化。这时候只要我们的LiveData数据有变化后就会调用前面的Observer实例的onChanged方法。
第三部分,给一个Button控件添加了一个点击事件,点击之后就会改变我们的LiveData属性的值。
这里修改值用的是setValue方法,而MultableLiveData还有一个postValue方法也是用来更新值的。它们的区别在于:setValue只能用于主线程,而postValue可以用于任意的线程,它底层是post一个值给主线程,因此下面的例子会先执行setValue再执行postValue
liveData.postValue("a")
liveData.setValue("b")
LiveData的转换
有时候我们想将包含一种类型的LiveData对象转换为另一种类型的LiveData对象。这时候就需要用到LiveData的转换了。
在Lifecycle的的包中包含了一个Transmformations类用于进行这样的转换。这个类有两个转换方法,一个是map方法、另一个是switchMap方法。下面我们分别通过实际的例子来进行学习。上面一节已经简单的看到了LiveData和ViewModel该如何进行配合使用。下面的例子重点放在转换上,我就只使用LiveData来进行说明了。
map
下面是包含一个name属性的User类
data class User(var name: String)
下面是在Activity中进行的转换操作
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
//一
val userLiveData = MutableLiveData()
userLiveData.value = User("anriku")
val userName: LiveData = Transformations.map(userLiveData) {
it.name
}
//二
userName.observe(this, Observer {
tv.text = it
})
//三
bt.setOnClickListener {
val user = User("anrikuwen")
userLiveData.value = user
}
}
}
在第一部分可以看到,实例化了一个MultableLiveData
转换的过程是将我们要转换的LiveData类作为第一个参数。然后它会将前面LiveData对应泛型类型的值传送到后面要实现的Function接口中。map的Function接口返回我们要得到的LiveData的泛型类型的值
后面两部分添加观察者、为Button设置监听器就不讲了。但其中有一个非常重要的东西就是进行上面的转换后,如果改变了上游的(也就是被转换的)LiveData的值的时候。下游的LiveData值也会被改变。
switchMap
如果你已经清楚上面的map转换了,那么switchMap转换也就不是难事的。
下面是Activity中进行switchMap转换,我们修改的地方。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
val userName: LiveData = Transformations.switchMap(userLiveData) {
val data = MutableLiveData()
data.apply {
value = it.name
}
}
...
}
}
从上面的代码可以看到switchMap的第二部分的Function的函数式接口要返回的是一个LiveData对象。这里就返回了LiveData
上面两个函数其实就是第二函数式接口的返回值不同。而且在这里你会发现一个问题用Java代码写的函数式接口在Kotlin中调用的时候可以化简为上面这样的lambada表达式。但是用Kotlin写的函数式接口不能化简为上面的lambada表达式,而应该使用匿名对象
LiveData和DataBinding的使用
下面是xml中的代码:
这里看到TextView,这里显示的一个NameViewModel的mCurrentName的LiveData。
class LiveDataActivity : AppCompatActivity() {
private lateinit var mNameViewModel: NameViewModel
private lateinit var mActivityLiveDataBinding: ActivityLiveDataBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mActivityLiveDataBinding = DataBindingUtil.setContentView
(this,R.layout.activity_live_data)
mNameViewModel = ViewModelProviders.of(this).get(NameViewModel::class.java)
//Look Here
mActivityLiveDataBinding.nameViewModel = mNameViewModel
mActivityLiveDataBinding.setLifecycleOwner(this)
bt.setOnClickListener{
mNameViewModel.mCurrentName?.value = "anriku${mNameViewModel.index}"
mNameViewModel.index++
}
}
}
上面看到Look Here
注释下面的代码,这里给mActivityLiveDataBinding设置了nameViewModel。setLifecycleOwner(this)让其可以像Observablexxx那样在数据发生改变后就反馈给对应的UI,这样设置了,也不在需要像上面一样添加观察者了。完美与Databinding进行结合,这也是个人认为可以完全替代Observablexxx的原因了。或许是还有些东西我还没发现吧。
MediatorLiveData
前面使用的MultableLiveData,每个这样的类都需要注册对应的观察者来进行属性变化的监视。MediatorLiveData类是一个将所有前面的MultableLiveData添加到自己类中。然后只用自己一个类来进行观察观察者注册就行。
具体例子如下:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
val firstName = MutableLiveData()
firstName.value = "anriku"
val lastName = MutableLiveData()
lastName.value = "wen"
val liveDataMerger = MediatorLiveData()
liveDataMerger.addSource(firstName) {
tv_first_name.text = it
}
liveDataMerger.addSource(lastName){
tv_last_name.text = it
}
liveDataMerger.observe(this, Observer {
})
bt.setOnClickListener{
lastName.value = "an"
}
}
}
我们前面两个MultableLiveData对象都没有调用observe方法而是将其添加到MediatorLiveData对象中去的。最后我们只需要调用MediatorLiveData的observe方法就行。你还可以通removeSource来删掉其中的某个LiveData对象。
总结
这篇博客主要将了LiveData相关的使用。其实主要就是两个子类的使用:
- MultableLiveData的使用
- LiveData与DataBinding的结合
- MediatorLiveData的使用
参考
官方文档