要点:
①ViewModel负责准备和管理Activity、Fragment等UI相关的数据。
②ViewModel+LiveData可以用于处理Activity、Fragment与应用其他部分的通信,比如调用业务逻辑类。
③由于配置修改(比如旋转屏幕)而导致的Activity重建,不会丢失界面数据。
④ViewModel数据是存储在Activity中的,因此ViewModel还可以用于同一Activity中的多个Fragment间的通信。
1.ViewModel
ViewModel是Jetpack的一部分。 ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。
ViewModel出现的背景:
①职责分离
为了能够更好地将职能划分,Android提供了ViewModel类,专门用于存放应用程序页面所需的数据。
②数据保留不丢失
在Android中如果Activity、Fragment销毁或者重建,存储在其中的数据会丢失。对于简单的数据,Activity可以使用onSaveInstanceState()方法来从onCreate()中恢复数据,但这个方法只适合可以序列化再反序列化的少量数据,而不适合较大的数据。
③防止异步操作时内存泄露
UI界面经常需要异步操作,比如网络请求等,当界面销毁时往往需要手动维护异步取消的动作,这样显得特别繁琐,并且把所有代码都写在界面中,会变得特别臃肿。
于是就需要将视图数据与界面分离,让层次清晰且高效。ViewModel作为视图数据和界面的桥梁,用来存储与UI相关的数据,它通过lifecycle感知的方式存储和管理UI相关数据。它可以维护自己的生命周期,不需要手动操作,这无疑大大降低开发难度。
ViewModel的生命周期:
这是在没有任何设置的情况下,旋转屏幕时Activity的生命周期变化和ViewModel的生命周期。可以看到旋转屏幕导致Activity重建时,ViewModel中的数据不会被清理。即ViewModel类使得数据在配置更改(如屏幕旋转)时保活。
从这张图可以看出:
①ViewModel的生命周期比创建它的Activity、Fragment的生命周期都要长,即ViewModel中的数据会一直存活在Activity/Fragment中。因此ViewModel不能持有Context的对象,否则会出现内存泄露。
也就是说ViewModel一直保留在内存中,直到它的作用域永久消失:在activity的情况下,当它finishes时;而在fragment的情况下,当它被detached时。
②Activity在生命周期中可能会触发多次onCreate(),而ViewModel只会在第一次onCreate()时创建,然后直到最后Activity销毁。
ViewModel的应用:
屏幕旋转后,使用户操作数据仍然存在。
2.ViewModel的使用
①写一个类继承自ViewModel
class MyViewModel : ViewModel() {
private var number:Int = 0
fun getNumber(): Int {
return number
}
fun setNumber() {
number++
}
override fun onCleared() {
super.onCleared()
//viewModel销毁时调用,可以做一些释放资源的操作,防止内存泄露
}
}
②使用自定义的ViewModel
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myViewModel = ViewModelProvider( this).get(MyViewModel::class.java)
btn_add.setOnClickListener {
myViewModel.setNumber()
tv_text.setText("" + myViewModel.getNumber())
}
}
}
点击Button可以使TextView上的数字一直增加,而且旋转屏幕时数据也会保持,不会丢失(如果不使用ViewModel,旋转屏幕时TextView上的数据会变为0)。
ViewModel是一个抽象类,只有一个onCleared()方法。当ViewModel不再被需要,即与之相关的Activity/Fragment被销毁时,该方法会被系统调用。因此可以在该方法中执行一些资源释放的相关操作,防止造成内存泄露。注意: 当屏幕旋转而导致的Activity重建,并不会调用该方法。
注意:
①如果Activity重新创建,它接收的ViewModel实例与第一个Activity创建的实例相同。
②当Activity完成(不能简单理解为destroy)时,框架会调用ViewModel的onCleared()方法,以便它可以