gpt4 book ai didi

kotlin - 在 Android Compose 的 View 模型中使用 State 是一种好方法吗?

转载 作者:行者123 更新时间:2023-12-05 09:30:16 29 4
gpt4 key购买 nike

我已经阅读了一些学习 Compose 的示例代码。

我发现许多示例项目使用代码 A 在 View 模型中创建一个 StateFlow,然后在 @Composable 函数中将其转换为 State,当 drawerOpen 改变时,UI 会自动更新。

1:我觉得Code B和Code C都可以做同样的事情,对吧?为什么很多项目很少用到它们?

2:代码A是好方法吗?

3: 我不需要为 @Composable fun myRoute(...) 中的变量 drawerOpen 添加 rememberSaveable 因为 View 模型会存储数据,对吧?

代码A

class MainViewModel : ViewModel() {
private val _drawerShouldBeOpened = MutableStateFlow(false)
val drawerShouldBeOpened: StateFlow<Boolean> = _drawerShouldBeOpened
...
}

@Composable
fun myRoute(
val drawerOpen by MainViewModel.drawerShouldBeOpened.collectAsState() //Do I need add rememberSaveable ?
...
}

代码B

class MainViewModel : ViewModel() {
private var _drawerShouldBeOpened = mutableStateOf(false)
val drawerShouldBeOpened: State<Boolean> = _drawerShouldBeOpened
...
}

@Composable
fun myRoute(
val drawerOpen = MainViewModel.drawerShouldBeOpened //Do I need add rememberSaveable ?
...
}

代码 C

class MainViewModel : ViewModel() {
private var _drawerShouldBeOpened = false
val drawerShouldBeOpened: Boolean = _drawerShouldBeOpened
...

}

@Composable
fun myRoute(
val drawerOpen = rememberSaveable { mutableStateOf(MainViewModel.drawerShouldBeOpened)) //Can I remove rememberSaveable ?

}

最佳答案

这里有多个问题。
让我尽可能回答。

<强>1。你应该在哪里使用remember/rememberSaveable? (代码 A、B 或 C)

仅在代码 C 中是必需的。
(在代码 A 和 B 中使用也没有问题,但没有优势)

原因,
在代码 A 和 B 中——状态在 View 模型中维护。因此,该值在重组后仍然存在。
但在代码 C 中,状态是在可组合项内部创建和维护的。因此,记住 是使值在重组后仍然存在所必需的。

More details in Docs

<强>2。为什么Code C用得不多?

只要状态发生变化而不是值发生变化,就会发生可组合重组。

下面给出了一个简单的例子来证明这一点。

class ToggleViewModel : ViewModel() {
private val _enabledStateFlow = MutableStateFlow(false)
val enabledStateFlow: StateFlow<Boolean> = _enabledStateFlow

private val _enabledState = mutableStateOf(false)
val enabledState: State<Boolean> = _enabledState

private var _enabled = false
val enabled: Boolean = _enabled

fun setEnabledStateFlow(isEnabled: Boolean) {
_enabledStateFlow.value = isEnabled
}

fun setEnabledState(isEnabled: Boolean) {
_enabledState.value = isEnabled
}

fun setEnabled(isEnabled: Boolean) {
_enabled = isEnabled
}
}

@Composable
fun BooleanToggle(
viewmodel: ToggleViewModel = ToggleViewModel(),
) {
val enabledStateFlow by viewmodel.enabledStateFlow.collectAsState()
val enabledState by viewmodel.enabledState
val enabled by rememberSaveable {
mutableStateOf(viewmodel.enabled)
}

Column {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
) {
Text(text = if (enabledStateFlow) {
"Enabled"
} else {
"Disabled"
})
Button(onClick = { viewmodel.setEnabledStateFlow(!enabledStateFlow) }) {
Text("Toggle State Flow")
}
}

Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
) {
Text(text = if (enabledState) {
"Enabled"
} else {
"Disabled"
})
Button(onClick = { viewmodel.setEnabledState(!enabledState) }) {
Text("Toggle State")
}
}

Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
) {
Text(text = if (enabled) {
"Enabled"
} else {
"Disabled"
})
Button(onClick = { viewmodel.setEnabled(!enabled) }) {
Text("Toggle Value")
}
}
}
}

你可以看到第三个文本不会在点击按钮时更新。
原因是可组合项内的可变状态是使用 View 模型数据中的初始值创建的。但对该数据的进一步更新不会反射(reflect)在可组合项中。

要获取更新,我们必须使用响应式数据,例如 FlowLiveDataState 及其变体。

<强>3。使用 StateFlowState

来自docs ,可以看到compose支持FlowLiveDataRxJava

您可以在用法中看到我们正在为 StateFlow 使用 collectAsState()。该方法将 StateFlow 转换为 State。所以两者都可以使用。

如果 ViewModel 之外的层(如 repo)是数据源并且它们使用 Flow 数据类型,则使用 Flow
否则 MutableState 应该没问题。

关于kotlin - 在 Android Compose 的 View 模型中使用 State<Boolean> 是一种好方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69763249/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com