ViewModel实现和原理
前言
ViewModel的主要基于观察者的设计模式,他主要分为两个部分:
- 提供者Provider:在我们这里就是数据的提供者,当实体的数据改变的时候,会自动通知所有观察者,观察者收到通知后就可以做对应的数据。
- 观察者Observer:观察者注册提供程序,当提供者每次发送通知的时候,观察者就会做对应的处理。
其最终实现出来的效果就是,在代码中,一旦我们注册的实体对象里面的数据改变之后,对应的UI就会自动的进行更新,这样数据更新的代码我们只需要在观察者里面写一套,不需要反复写多套了。
提供者和观察者是一对多的关系,也就是一个提供者可以被很多个观察者注册
1. 使用
1.1 gradle准备
在用上ViewModel之前,需要在项目的build.gradle中加上如下内容,开启DataBinding。
为了写ui方便我把ViewBinding也加上了,他不是必须的,但是我的demo代码里面会有ViewBinding相关内容。
android {
buildFeatures {
dataBinding = true
viewBinding = true
}
}
1.2 模拟场景
我们模拟一个简单的场景,页面里面就三个TextView,两个按钮,我们的目标就是用ViewModel来完成点了按钮之后他的Text就动态修改的功能。
实体是我随便设置的
class Student(var name: String = "",
var age: Int = 0,
var id: String = "")
页面长这样,三个TextView和两个按钮
1.3. LiveData和ViewModel
任何一个ViewModel的动态更新都需要围绕LiveData和ViewModel这两个类进行
LiveData:将实体动态化,可以被具有生命周期的对象观察到,只有这个目标对象的生命周期处于活动中,才会收到通知。
ViewModel:通信类,LiveData通过ViewModel来下发通知。
所以我们的代码最后写成这样:
ViewModel作为容器类,里面的成员变量是一个Student的LiveData类(一般都用MutableLiveData,如果有特殊需求也可以自己写)。
如果实际开发的时候有多个这样需要通信的实体,都丢到自定义的ViewModel类里面
class StudentViewModel : ViewModel() {
private var student = MutableLiveData<Student>()
fun getStudent(): MutableLiveData<Student> {
return student
}
}
注册通知的方式也很简单,先通过ViewModelProvider生成一个ViewModel的实体,然后将对应的实体进行观察者的注册即可。
lass ViewModelActivity : AppCompatActivity() {
private lateinit var binding: ActivityViewModelBinding
private lateinit var viewModel: StudentViewModel
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityViewModelBinding.inflate(layoutInflater)
setContentView(binding.root)
// 创建ViewModel实体的固定写法
viewModel = ViewModelProvider(this).get(StudentViewModel::class.java)
// 注册Student对象,这样Student这个对象一旦改变,就会自动调用这里面的方法
viewModel.getStudent().observe(this) {
binding.vmName.text = "姓名:${
it.name}"
binding.vmAge.text = "年龄:${
it.age}"
binding.vmId.text = "id:${
it.id}"
}
}
}
1.4 更新数据
更新数据有两种方式:
setValue:整个对象改变之后,他会自动的通知更新。
post:只改变目标对象里面的一两个成员变量时,通过Post进行更新。
class ViewModelActivity : AppCompatActivity() {
private lateinit var binding: ActivityViewModelBinding
private lateinit var viewModel: StudentViewModel
@SuppressLint