在谷歌官方提供的安卓架构组件中,有ViewModel、LiveData、Lifecycle、DataBinding等,他们共同组成了一个完整的MVVM架构,实现了视图与业务逻辑分离,并且提供友好的生命周期管理。本文不会涉及到这些组件的原理解析,百度能找到一堆的我就不重复造轮子了,直接上干货教你如何使用。
在使用这些组件之前,我们先来了解下MVVM:
MVVM即 Model(数据) View(视图) ViewModel(数据视图管理器)
具体体现:
Model:bean(实体类)、网络请求相关、数据库相关
View:布局、View、Activity、Fragment 等UI相关
ViewModel:类似于MVP中的Presenter,用于从Model获取信息,传递给View进行显示,ViewModel与View是绑定在一起的,通过一定手段进行数据交互(例如LiveData)
LiveData
是可观察的数据持有者类。它具有生命周期感知功能,这意味着它能响应其他应用程序组件(例如Activity、Fragment或Service)的生命周期。这确保LiveData仅更新处于活动的生命周期状态的应用程序组件观察者。
在使用LiveData之前,你可以先去了解官方文档Lifecycle,或者查看我的博客:《安卓架构组件实战——Lifecycle》
ViewModel:用于Model层和View层数据交互的中间组件,架构组件为ViewModel
UI控制器提供了帮助程序类,该类负责为UI准备数据。 ViewModel
配置更改期间会自动保留对象,以便它们保存的数据可立即用于下一个Activity或Fragment实例。
View和ViewModel通过LiveData来传递消息和数据。LiveData是一个可观察的数据持有者,他可以让应用程序组件去观察LiveData中的数据是否发生改变。LiveData还会遵循应用程序组件(Activity,Fragment, Service)的生命周期状态来避免内存泄露,从而使你的APP不会消费太多的内存(LiveData具备生命周期感知。这意味着除非Activity/fragment是激活状态(onStart但是还没有onStop),要不然是不会发起回调的。当fragment调用onStop后, LiveData还会自动删除观察者)
LiveData通常和ViewModel一起使用,使用方法如下:
1.引入
//lifecycle
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
//ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-rc02"
非androidx版本:(注意编译版本28以上,引入的support库也必须是28.0.0以上的)
// Lifecycle
implementation "android.arch.lifecycle:extensions:1.1.0"
//ViewModel
implementation "android.arch.lifecycle:viewmodel:1.1.0"
//LiveData
implementation "android.arch.lifecycle:livedata:1.1.0"
LiveData 是一个抽象类,它的实现子类有 MutableLiveData ,MediatorLiveData,常用的是 MutableLiveData。
使用如下:
继承ViewModel即可(kotlin写法,使用java的童鞋请自行翻译)
/**
* 基础的ViewModel,可以封装一些通用操作
*
*/
abstract class BaseViewModel : ViewModel(){
}
LiveData:
class HomeViewModel : BaseViewModel() {
//定义一个MutableLiveData,设置Value即可
val data = MutableLiveData()
fun setData(name: String) {
//这里可以去获取网络数据,操作数据库等
//主线程可以使用setValue() ,异步线程使用postValue()
data.value = name
}
}
在Fragment监听数据变化:
class HomeFragment : BaseFragment() {
...省略部分代码
private var homeViewModel: HomeViewModel? = null
companion object {
fun newInstance(): HomeFragment {
return HomeFragment()
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//获取ViewModel实例(如果我的ViewModele需要带参数怎么办?看文章后面)
homeViewModel = ViewModelProviders.of(this)[HomeViewModel::class.java]
//改变数据
homeViewModel?.setData("测试")
//监听ViewModel里面的data的数据变化
// homeViewModel?.data?.observe(this,Observer{data->{
// } })
homeViewModel?.data?.observe(this, Observer {
mProgressDialog?.hide()
Log.i("test", it)
})
}
}
这样就完成了LiveData和ViewModel的集成,不用我们去关注生命周期的事,简单明了,完整的代码请看:项目源码
我们刚刚发现了,在Fragment获取ViewModel实例是通过如下方式获取的:
homeViewModel = ViewModelProviders.of(this)[HomeViewModel::class.java]
这里它会去执行HomeViewModel的无参构造函数,那么我的ViewModel构造函数带参数怎么办?
ViewModelProviders.of方法里面提供了一种方法,传入一个ViewModelProviders.Factory对象即可,具体写法:
//构造函数带参数tips
class MyViewModel(private val tips:String?) :BaseViewModel() {
val timeData = MutableLiveData()
init {
val timer = Timer()
timer.schedule(object : TimerTask() {
override fun run() {
val dataStr = TimeUtil.dateToSecondStr(Date())
//异步线程使用postValue(),主线程用setValue()/postValue()
timeData.postValue(tips+dataStr)
}
},0,1000)
}
//构造函数带参数,需要构建一个Factory,这样就可以用
//ViewModelProviders.of(this, MyViewModel.Factory(tips)).get(MyViewModel::class.java)执行带参数的构造函数
class Factory(private val tips:String?) : ViewModelProvider.Factory{
override fun create(modelClass: Class): T {
return MyViewModel(tips) as T
}
}
}
调用:
myViewModel = ViewModelProviders.of(this, MyViewModel.Factory("当前时间:")).get(MyViewModel::class.java)