我可以在ViewModel中创建MutableState属性,但在Android Jetpack Compose中将其作为不可变属性向屏幕公开吗?

e4yzc0pl  于 2023-02-27  发布在  Android
关注(0)|答案(2)|浏览(380)

在我的ViewModel中,我有MutableState属性,我只想在ViewModel中更改它们的.value,而不是在屏幕中。
这很容易通过以下两个属性来解决

private val _someScreenState = mutableStateOf("something")
val someScreenState: State<String> = _someScreenState

但是当有很多属性时,这会变得看起来很烦人,工作起来很混乱。那么有没有办法做同样的事情,但不必安装两个State属性呢?
我知道Kotlin有一个很好的方法来编写类内部属性的getter和setter,例如

var someScreenState = mutableStateOf("something")
    private set()

这样就可以了,因为属性本身是一个var(可变的),同时有一个私有的setter.但是对于compose的State,我并不想改变属性本身,而是改变它的someScreenState.value属性,所以你仍然可以在ViewModel之外改变someScreenState.value.
我已经使用了状态对象,比如ScreenState类,它包含了所有的State属性,但是很多属性必须是StateFlow类型,对于状态对象,你不能挑选哪个是State,哪个是StateFlow(状态对象还有其他问题,这就是为什么我一直试图远离它们)。

h22fl7wq

h22fl7wq1#

这可以通过对Kotlin支持属性进行新的实验性修改来实现,该特性需要Kotlin 1.7,一个新的K2编译器,以及一些修改来启用它。
应该是这样的。
(This可能不是确切的语法,因为它是实验性的,因为围绕这一点已经有很多讨论很长时间了)

相关文章
https://nikoladespotoski.medium.com/overriding-backing-property-type-in-kotlin-1-7-5581cd30e77a
相关GitHub问题供全面讨论参考,
https://github.com/Kotlin/KEEP/issues/278
YouTrack问题链接
https://youtrack.jetbrains.com/issue/KT-14663

hjzp0vay

hjzp0vay2#

你可以这样写:

var state by mutableStateOf("something") //Type is String
    private set

注意,我在这里使用的是kotlin委托,您将获得类型String而不是MutableState<String>,将其与private set组合,现在您的对象为var,您可以直接在视图模型中设置它,并且它在可组合对象中将是不可变的。而且你仍然可以用这种方式观察state的变化。我认为它使用起来也更干净,因为你可以在没有.value的情况下直接访问值
但是,值得一提的是,by委托仅适用于组合State,而不适用于StateFlow

    • 示例:**

视图模型:

class MainViewModel: ViewModel() {

    var textFieldValue: String by mutableStateOf("")
        private set

    fun onTextFieldValueChange(newValue: String) {
        textFieldValue = newValue
    }
}

可组合:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Screen(viewModel: MainViewModel = viewModel()) {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    )  {
        OutlinedTextField(
            label = { Text(text = "Enter your name") },
            value = viewModel.textFieldValue,
            onValueChange = { value -> viewModel.onTextFieldValueChange(value) },
        )
    }
}

结果:

如您所见,我能够观察文本字段值的更改,这些更改成功地反映在可组合

相关问题