我推导出了StateOf,它使用3个不同的状态:heightValueisOkselectedOption,这在(selectedOption, onOptionSelected)中被解构,可能就是原因.除非我在remember(selectedOption)中指定,否则它不会响应selectedOption中的更改.我试图理解为什么以及我的修复是否是正确的修复,或者我应该以不同的方式处理解构.

val radioOptions = listOf("A", "B", "C", "D")
var heightValue by remember { mutableIntStateOf() }
var isOk by remember { mutableStateOf(true) }
val (selectedOption, onOptionSelected) = remember { mutableStateOf(radioOptions[0]) }

//val calculatedValue by remember() { /*This won't work. Next line is the fix*/
val calculatedValue by remember(selectedOption) {
    derivedStateOf {
        calcNewValueInch(
            pickerValue = heightValue,
            isOk = isOk,
            selectedOption = selectedOption,
        )
    }
}

推荐答案

derivedStateOf仅适用于State对象.selectedOption不是一个州,因此它的任何更改都不会被检测到.

让我们更详细地看看这个.在您最初的非工作示例中,只有remember()derivedStateOf在第一次合成时执行.它还执行Lambda并跟踪所有使用的State对象.我们预计情况如下:

  1. heightValue
  2. isOk
  3. selectedOption

那么derivedStateOf的结果就是remember ed,因此在重新组合时不会再次执行.没关系:当上述列表中的任何状态发生变化时,现在创建的派生状态会自动更新.

除了它只适用于1.和2.,它对3不起作用.

由于derivedStateOf只跟踪其Lambda中使用的实际State个对象,因此很明显,它不会在3时更新.更改:selectedOption只是一个简单的字符串,而不是State.更有趣的问题是为什么它does适用于1.和2.不过,由于它们是also个无州,只有Int和布尔值.但这并不完全正确.它们实际上是您使用by关键字检索到的委托.这意味着您可以将它们用作简单的Int和布尔值,但每当读取它们的值时,委托对象的getValue函数实际上就会执行.当设置它们的值时,将改为调用setValue.Kotlin向您隐藏了所有这些,以便您的代码看起来更干净,但这就是访问委托时实际发生的情况.最后,1.和2.一个州是delegates个,因此derivedStateOf个州可以看到这些州并监控它们的变化.

然而,selectedOption是通过解构MutableState创建的.这给您留下了一个简单的字符串,其中包含解构时的值.棘手的是,对于大多数情况下,这就足够了,所以感觉与委托州没有太大不同:

Text(selectedOption) 

这将按预期工作,并在每次基础状态selectedOption更改时更新.这是因为Compose运行时会跟踪所有State读取,而解构State也算作如此.当状态发生变化时,它就会重新组合功能,因此解构被重复并更新selectedOption.但derivedStateOf位于remember之后,不受此类重组的影响.这就是为什么它会跟踪所有State对象本身.但它从来没有看到selectedOption后面国家的解构,所以它只看到了结果,那是一个简单的字符串,而不是一个国家.

我们现在可以修改上面derivedStateOf个跟踪的州列表:

  1. heightValue名代表背后的国家反对
  2. isOk名代表背后的国家反对
  3. Not selectedOption,因为这只是一个简单的字符串

Lambda中访问的唯一州是1.和2.,所以无论你用3.做什么,它不会影响derivedStateOf.

当您使用remember(selectedOption)时,它似乎有效,但实际发生的情况是,每次selectedOption更改并创建一个新的状态时,整个派生状态就会被丢弃.再次执行Lambda,并创建上述应观察更改的State对象列表,但3并不重要.实际上并不在列表中,因为当它发生变化时,您只需创建一个new派生State对象,就不会让current派生State对象更新.

解决这个问题的正确方法是将国家控制在selectedOption左右.或者像处理1一样委托它.和2.,或者如果出于某种原因您不想这样做,则可以这样做:

val selectedOptionState = remember { mutableStateOf(radioOptions[0]) }
val (selectedOption, onOptionSelected) = selectedOptionState

val calculatedValue by remember {
    derivedStateOf {
        calcNewValueInch(
            pickerValue = heightValue,
            isOk = isOk,
            selectedOption = selectedOptionState.value, // this accesses the State now
        )
    }
}

在这种情况下,我建议您完全删除解构,只访问selectedOptionState.value,这样代码的读者就不会想知道为什么您有时使用这个,有时使用那个来访问同一个州.

Android相关问答推荐

derivedState Of没有响应.帮助我理解为什么

Android使用参数编写齐射后请求

NativeScript在`ns run android`上重复Kotlin类

Jetpack创作动画断断续续变化的观点

Android Kotlin ImageView内置于Kotlin ImageView中.适配器未按预期更新

如何在Android中打印到命令行

如何在 Jetpack Compose LazyColumn 中将项目分组在一起,例如卡片

如何在 Android Studio 中为带有 Room 的 SQLite 编写需要参数的查询?

如何在 Jetpack Compose 中对齐按钮底部中心?

使用 Dagger Hilt 获取接口的所有实例

在 Jetpack Compose 中包装内容

Android:appcompat 和 material 如何从默认创建 appcompat 和 material 视图?

如何放置在柱子的角落(底端)

如何限制键盘输入键不允许在下一行输入(Android Jetpack Compose 中的 TextField)

使用 capacitor cordova 插件的 Android Studio 错误

从expose 的 dropdownMenu 可组合、jetpack 组合中 Select 选项时,不会触发文本字段的 onValueChange

如何将文本组合放在行中,一个具有可变宽度的组合

在 android list 中添加 IsMonitoringTool 元数据标志的位置

线圈单元测试 - 如何做到这一点?

WindowManager 内的 RecyclerView 不更新