前言
将应用的界面数据与界面(Activity
/Fragment
)分离可以让您更好地遵循我们前面讨论的单一责任原则。activity 和 fragment 负责将视图和数据绘制到屏幕上,而 ViewModel
则负责存储并处理界面所需的所有数据。
数据变量从 XXFragment
移至 XXViewModel
类
- 将数据变量
score
、currentWordCount
、currentScrambledWord
移至XXViewModel
类。
class XXViewModel : ViewModel() {
private var score = 0
private var currentWordCount = 0
private var currentScrambledWord = "test"
...
请注意这些属性仅对
ViewModel
可见,界面无法对其进行访问
想要解决此问题,就不能将这些属性的可见性修饰符设为 public
,不应该让数据可被其他类修改。因为外部类可能会以不符合视图模型中指定的游戏规则的预料外方式对数据做出更改。外部类有可能会将 score
更改为其他错误的值。
在 ViewModel
之内,数据应可修改,数据应设为 private
和 var
。而在 ViewModel
之外,数据应可读取但无法修改,因此数据应作为 public
和 val
公开。为了实现此行为,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
本文正在参加「金石计划」