上一篇中讲到了viewmodel,当我点击那个自增按钮时,并不能立刻看到数字显示变化。需要我们重新进入界面,因为我把界面刷新写在了onResume()中。那么是否有方法,当我的数据变化时,那些与该数据绑定的UI能立刻自动刷新呢?鉴于这种需要,Livedata就登场了!!!
1、Livedata是什么?
答:Livedata是一种增强型的观察者模式,增强之处在于它能感知到生命周期。当被观察者的数据发生变化,和Livedata绑定的生命周期组件处于活跃状态时,才会被通知,如果处于不活跃状态,那么不会收到数据的通知。
2.使用Livedata能带来什么好处?
答:1、避免处理回调异常情况。开发中,譬如我们需要将指定的网络数据展示到一个界面上,我们一般是异步访问网络,在回调中去更新UI。回调有时候是不可控的,出现的很多情况是,网络回调后,用户已经退出了UI界面,这个时候就不需要再去显示UI,并且很可能因为UI不可见,导致出现一个空指针异常。
2、功能代码更集中。一般情况多处UI都需要关联某个数据,那么使用livedata,就可以使得UI控制更集中,不用到处在更新UI,导致代码维护不可控。
3、链式更新。譬如:有a.b.c三个数据(不限制一定要是数据,也有可能是函数),c依赖b,b依赖a,使用livedata就能做到,当a改变时,b和c也能跟着改变,代码写起来真是非常顺手加简单,看后面的例子时就会有这个感受。
3、怎么使用Livedata?
我们继续使用上篇中的viewmodel例子,只是将Viewmodel中的Int字段替换为了Livedata字段。
- 构建Viewmodel
class BlankViewModel : ViewModel() {
var number = MutableLiveData<Int>()
//这个map就是我上面说到的链式更新,当number变化时,会自动调用map中的函数,并更新score的返回值
var score = Transformations.map(number) {
it?.times(10)
}
}
2、在Fragment中获取Livedata.
首先是Fragment01,其中有个按钮,点击后呢viewmodel中的number字段自增1。
class BlankFragment01 : Fragment() {
private lateinit var viewModel: BlankViewModel
override fun onAttach(context: Context?) {
super.onAttach(context)
viewModel = ViewModelProviders.of(activity as FragmentActivity).get(BlankViewModel::class.java)
viewModel.number.observe(activity as FragmentActivity,object :Observer<Int>{
override fun onChanged(t: Int?) {
number_tv_01.setText(viewModel.number.value?.toString())
}
})
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// kotlin中可以直接使用布局文件中的控件id来操作该view,但是前提是在onViewCreated中使用。
increase.setOnClickListener {
//注意这里的判空,livedata中的值未设置时,value字段是null
if (viewModel.number.value == null) {
viewModel.number.value=1
}else{
var value = viewModel.number.value
viewModel.number.value = value?.inc()
}
}
}
接下来是Fragment02,我们对同一个的viewmodel进行观察
class BlankFragment02 : Fragment() {
private lateinit var viewModel: BlankViewModel
override fun onAttach(context: Context?) {
super.onAttach(context)
viewModel = ViewModelProviders.of(activity as FragmentActivity).get(BlankViewModel::class.java)
//添加observe方法就能添加观察了,当score livedata数据发生变化时,onChange()回调就会自动执行
viewModel.score.observe(activity as FragmentActivity,object :Observer<Int?>{
override fun onChanged(t: Int?) {
number_tv.text = t?.toString()
}
})
}
}
效果如下Gif所示,当我点击按钮时,viewmodel中的number自增1,同时每当number变化时,就会调用map中的lambda表达式,并修改score的值,所以number变化,会引起score的链式变化。
var score = Transformations.map(number) {
it?.times(10)
}