Android ViewModel

292 阅读2分钟

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)
    }