前言

将应用的界面数据与界面(Activity/Fragment)分离可以让您更好地遵循我们前面讨论的单一责任原则。activity 和 fragment 负责将视图和数据绘制到屏幕上,而 ViewModel 则负责存储并处理界面所需的所有数据。

数据变量XXFragment 移至 XXViewModel

  1. 将数据变量 scorecurrentWordCountcurrentScrambledWord 移至 XXViewModel 类。
class XXViewModel : ViewModel() {
    private var score = 0
    private var currentWordCount = 0
    private var currentScrambledWord = "test"
...

请注意这些属性仅对 ViewModel 可见,界面无法对其进行访问

想要解决此问题,就不能将这些属性的可见性修饰符设为 public,不应该让数据可被其他类修改。因为外部类可能会以不符合视图模型中指定的游戏规则的预料外方式对数据做出更改。外部类有可能会将 score 更改为其他错误的值。

ViewModel 之内,数据应可修改,数据应设为 privatevar。而在 ViewModel 之外,数据应可读取但无法修改,因此数据应作为 publicval 公开。为了实现此行为,Kotlin 提供了称为后备属性的功能。

后备属性

使用后备属性,可以从 getter 返回确切对象之外的某些其他内容。

Kotlin 框架会为每个属性生成 getter 和 setter。

对于 getter 和 setter 方法,可以替换其中一个方法或同时替换两个方法,并提供自定义行为。为了实现后备属性,需要替换 getter 方法以返回只读版本的数据。后备属性示例:

private var _count = 0
val count: Int
   get() = _count

举例而言,在应用中,需要应用数据仅对 ViewModel 可见:

ViewModel 类之内:

  • _count 属性设为 private 且可变。因此,只能在 ViewModel 类中对其访问和修改。惯例是为 private 属性添加下划线前缀。

ViewModel 类之外:

  • Kotlin 中的默认可见性修饰符为 public,因此 count 是公共属性,可从界面控制器等其他类对其进行访问。由于只有 get() 方法会被替换,所以此属性不可变且为只读状态。当外部类访问此属性时,它会返回 _count 的值且其值无法修改。这可以防止外部类擅自对 ViewModel 内的应用数据进行不安全的更改,但允许外部调用方安全地访问该应用数据的值。

将后备属性添加到 currentScrambledWord

  • XXViewModel 中,更改 currentScrambledWord 声明以添加一个后备属性。现在,只能在 XXViewModel 中对 _currentScrambledWord 进行访问和修改。界面控制器 XXFragment 可以使用只读属性 currentScrambledWord 读取其值。
private var _currentScrambledWord = "test"
val currentScrambledWord: String
   get() = _currentScrambledWord
  • XXFragment 中,更新 updateNextWordOnScreen() 方法以使用只读的 viewModel 属性 currentScrambledWord
private fun updateNextWordOnScreen() {
   binding.textViewUnscrambledWord.text = viewModel.currentScrambledWord
}
  • XXFragment 中,删除 onSubmitWord()onSkipWord() 方法内的代码。稍后您将实现这些方法。现在,您应该能够不出错误地编译代码了。

注意:勿公开 ViewModel 中的可变数据字段,确保无法从其他类修改此数据。ViewModel 内的可变数据应始终设为 private

本文正在参加「金石计划」