如何在依赖于 MutableStateFlow 的 ViewModel 中维护密封类变体的状态

问题描述 投票:0回答:1

我有一段 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 没有使用它。 我怎样才能实现我想要做的事情?

android kotlin android-viewmodel kotlin-flow
1个回答
0
投票

您有 3 位信息要保存。测试选择和测试类中的值(一个字符串,一个整数)。测试类和视图模型的生命周期是多少? 在您的预览中,视图模型在预览功能内,将在旋转时重新创建。
通常视图模型将由诸如活动之类的东西拥有并传递给可组合函数。 您可以尝试在预览中的 vm 上使用 remember,但通常首选可组合函数是无状态的。

val vm = remember { viewModel<TestViewModel>() }

这将告诉 compose 记住 vm 的值,因此它将通过重组持续存在。

有一个处理组合、视图模型和封面旋转的代码实验室 https://developer.android.com/codelabs/basic-android-kotlin-compose-viewmodel-and-state#9

© www.soinside.com 2019 - 2024. All rights reserved.