我有一段 UI 取决于密封类的值。根据密封类的类型,此 UI 元素具有不同的形式。此外,密封类的每个变体都包含影响 UI 的变量,并且应该可以在屏幕旋转时进行修改和维护。这是一段代码,显示了我正在尝试做的事情:
class TestViewModel : ViewModel() {
enum class TestEnum { Test1, Test2 }
private val _choose = MutableStateFlow(TestEnum.Test1)
val choose = _choose.asStateFlow()
sealed class TestSealed {
class Test1(n : Int) : TestSealed() {
val n = MutableStateFlow(n)
}
class Test2(s : String) : TestSealed() {
val s = MutableStateFlow(s)
}
}
val test = choose.map {
when(it) {
TestEnum.Test1 -> TestSealed.Test1(0)
TestEnum.Test2 -> TestSealed.Test2("asd")
}
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), TestSealed.Test1(0))
fun toggle() {
viewModelScope.launch {
_choose.update {
when(it) {
TestEnum.Test1 -> TestEnum.Test2
TestEnum.Test2 -> TestEnum.Test1
}
}
}
}
}
@Preview
@Composable
fun TestPreview() {
AppTheme(true) {
Surface(Modifier.fillMaxSize()) {
val vm = viewModel<TestViewModel>()
Column {
Button(onClick = { vm.toggle() }) {
Text("toggle")
}
val test by vm.test.collectAsState()
when (val t = test) {
is TestViewModel.TestSealed.Test1 -> {
val n by t.n.collectAsState()
Button(onClick = { t.n.update { n + 1 } }) {
Text("increment")
}
Text("Test1 $n")
}
is TestViewModel.TestSealed.Test2 -> {
val s by t.s.collectAsState()
Button(onClick = { t.s.update { "foo" } }) {
Text("foo")
}
Text("Test2 $s")
}
}
}
}
}
}
这段代码几乎可以工作:问题是当我旋转屏幕时,变量
test
的当前值丢失了,我想保留它。但是我将n
和s
都存储在ViewModel
中是没有意义的,因为它们仅在choose
取其中一个值时使用。
我知道问题是 MutableStateFlow
中的 SealedTest
没有存储在 ViewModel 中,但我不知道如何才能更新和订阅 s
和 n
。从根本上说,问题在于决定绘制什么 UI 的变量 (test
) 也包含应该存储和保存的数据,但是将所述数据与 test
解耦意味着存储可能无用的数据,因为 UI 没有使用它。
我怎样才能实现我想要做的事情?
您有 3 位信息要保存。测试选择和测试类中的值(一个字符串,一个整数)。测试类和视图模型的生命周期是多少?
在您的预览中,视图模型在预览功能内,将在旋转时重新创建。
通常视图模型将由诸如活动之类的东西拥有并传递给可组合函数。
您可以尝试在预览中的 vm 上使用 remember,但通常首选可组合函数是无状态的。
val vm = remember { viewModel<TestViewModel>() }
这将告诉 compose 记住 vm 的值,因此它将通过重组持续存在。
有一个处理组合、视图模型和封面旋转的代码实验室 https://developer.android.com/codelabs/basic-android-kotlin-compose-viewmodel-and-state#9