ViewModel类以注重生命周期的方式存储和管理界面相关的数据。ViewModel类让数据可在发生屏幕旋转等配置更改后继续存在。
导入ViewModel依赖:
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-rc03'
架构组件为界面控制器提供了ViewModel辅助程序类,该类负责为界面准备数据。在配置更改期间会自动保留ViewModel对象,以便它们存储的数据立即可供下一个Activity或Fragment实例使用。
在实现我们自己的ViewModel时,只需要继承ViewModel或者AndroidViewModel类:
class ScoreViewModel : ViewModel() {
var scoreA = MutableLiveData<Int>().apply { value = 0 }
var scoreB = MutableLiveData<Int>().apply { value = 0 }
}
在kotlin中以下是根据预期目的选择作用域函数的简短指南:
对一个非空(non-null)对象执行 lambda 表达式:let
将表达式作为变量引入为局部作用域中:let
对象配置:apply
对象配置并且计算结果:run
在需要表达式的地方运行语句:非扩展的 run
附加效果:also
一个对象的一组函数调用:with
具体的请参考官方文档,www.kotlincn.net/docs/refere…
如果Activity重新创建,ViewModel实例与第一个Activity创建的实例相同。当所有者Activity完成时,框架会调用ViewModel对象的onCleared()方法,以便它可以清理资源。
接下来就是在Activity中使用ViewModel:
scoreViewModel = ViewModelProvider(this).get(ScoreViewModel::class.java)
创建ViewModel很简单就是这么一句代码,我们经常用到的可能是下面两个方法之一:
如果我们没有实现自定义的ViewModel工厂,那么就选择第一种方式。
如果我们需要给我们的ViewModel传递某些参数,那么我们就应该考虑通过Factory来创建了。
还是拿上面的例子来说,我们需要在进入页面的时候初始化TeamA和TeamB的分数,修改ViewModel如下:
class ScoreViewModel(
private val _scoreA: Int,
private val _scoreB: Int
) : ViewModel() {
val scoreA = MutableLiveData<Int>().apply { value = _scoreA }
val scoreB = MutableLiveData<Int>().apply { value = _scoreB }
}
接下来我们创建Factory:
class ScoreViewModelFactory(
private val scoreA: Int,
private val scoreB: Int
) : ViewModelProvider.NewInstanceFactory() {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return ScoreViewModel(scoreA, scoreB) as T
}
}
其中ViewModelProvider.NewInstanceFactory()返回的是一个最基础的factory:
我们需要重写create方法,传入相应的参数完成创建。
在Activity中使用:
scoreViewModel =
ViewModelProvider(this, ScoreViewModelFactory(10, 5)).get(ScoreViewModel::class.java)
此时我们已经传入了初始值,程序运行如下:
如果我们是在Fragment中使用,我们可以使用Kotlin委托属性来创建ViewModel:
class MyFragment : Fragment() {
val viewmodel: MYViewModel by viewmodels { myFactory }
}
那我们的例子来说的话就是:
private val scoreViewModel: ScoreViewModelFactory by viewModels {
InjectorUtils.InjectUtils.providerScoreViewModelFactory(10, 5)
}