Clarklevis' Workshop.

Android中的ViewModel

字数统计: 765阅读时长: 3 min
2021/08/18

ViewModel的一个重要作用就是帮助Activity分担一部分工作,专门用于存放与界面相关的数据,只要是界面上能看得到的数据,它的相关变量都应该存放在ViewModel中

ViewModel的生命周期和Activity是不同的,在手机屏幕旋转的时候,Activity会被重新创建,但是ViewModel不会,只有Activity退出的时候,ViewModel才会和Activity一起销毁

image-20210818212407408

ViewModel的基本用法

通常比较好的编程规范是给每一个Activity和Fragment都创建一个ViewModel

下面的程序可以做到在屏幕旋转的时候,界面上显示的数字是不变的

创建一个ViewModel类:

1
2
3
class MainViewModel : ViewModel() {
var counter = 0
}

绑定MainActivity和MainViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MainActivity : AppCompatActivity() {

lateinit var viewModel: MainViewModel

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val countReserve = sp.getInt("count_reserved",0)
//注意这里是通过ViewModeProvider去获得ViewModel的实例,而不是直接通过构造函数创建,不然每次调用onCreate方法时,都会创建一个ViewModel实例,ViewModel实例就不唯一了,就无法保存数据了
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
plus_one.setOnClickListener {
viewModel.counter++
refreshCounter()
}
refreshCounter()
}

//用于更新界面的数据
private fun refreshCounter(){
infoText.text = viewModel.counter.toString()
}
}

向ViewModel传递参数

下面的程序可以做到除了以上的功能外,还可以在退出程序后,重新打开的时候,界面显示的数字还是和之前一致的

重新更改MainViewModel的内容,添加一个参数:

1
2
3
4
//这样在创建ViewModel的时候可以将内容传进去,每次退出程序并重新打开后,可以通过构造方法构建这个ViewModel
class MainViewModel(val countReserve : Int) : ViewModel() {
var counter = countReserve
}

需要一个ViewModelProvider.Factory来为ViewModel传递参数(还是不能直接使用ViewModel的构造方法)

1
2
3
4
5
6
7
//这里面重写了create方法,并在里面创建了MainViewModel的额实例
class MainViewModelFactory(private val countReserve : Int) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MainViewModel(countReserve) as T
//因为这个方法的调用时机和Activity的生命周期无关,所以不会产生多个ViewModel被拆功能键的问题
}
}

更改MainActivity中的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class MainActivity : AppCompatActivity() {

lateinit var viewModel: MainViewModel
lateinit var sp : SharedPreferences

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

sp = getPreferences(MODE_PRIVATE)
//在程序重新运行的时候,从持久化中取出之前存入的值
val countReserve = sp.getInt("count_reserved",0)
//在这里传入Factory的实现类,并传入一个要传递给ViewModel构造函数的参数
viewModel = ViewModelProvider(this,MainViewModelFactory(countReserve))[MainViewModel::class.java]
//ViewModel更新操作
plus_one.setOnClickListener {
viewModel.counter++
refreshCounter()
}
//ViewModel清空操作
clear_btn.setOnClickListener {
viewModel.counter = 0
refreshCounter()
}
refreshCounter()

}
//在onPause的时候,将当前的ViewModel中的计数器的值放到sharedPreferences中持久化,以便在程序重新运行的时候被使用,可以保证不论是程序退出还是进入后台,计数都不会丢失
override fun onPause() {
super.onPause()
sp.edit {
putInt("count_reserved", viewModel.counter)
}
}

private fun refreshCounter(){
infoText.text = viewModel.counter.toString()
}
}
CATALOG
  1. 1. ViewModel的基本用法
    1. 1.1. 下面的程序可以做到在屏幕旋转的时候,界面上显示的数字是不变的
  2. 2. 向ViewModel传递参数