在 Codelab 的示例中,提供的超时不会改变,但它是虚构的,因为它可能会改变许多默认的可组合使用
rememberUpdatedState这是
@Composable
fun <T> rememberUpdatedState(newValue: T): State<T> = remember {
mutableStateOf(newValue)
}.apply { value = newValue }
正如您在下面的问题和评论中一样,它也可以用作
var currentOnTimeout by remember(mutableStateOf(onTimeout))
currentTimeout = onTimeout
它看起来不如 rememberUpdatedState 但两者都有效。这是您可以为同一目的选择的偏好或选项。
Slider 和许多其他 Composable 也使用 rememberUpdatedState
@Composable
fun Slider(
value: Float,
onValueChange: (Float) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
/*@IntRange(from = 0)*/
steps: Int = 0,
onValueChangeFinished: (() -> Unit)? = null,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
colors: SliderColors = SliderDefaults.colors()
) {
require(steps >= 0) { "steps should be >= 0" }
val onValueChangeState = rememberUpdatedState(onValueChange)
}
即使您提供的onValueChange 函数在大多数情况下都不会更改,可能在少数情况下它可能需要更改,使用rememberUpdatedState 以确保将回调的最新值传递给Slider。
Slider(
value = value,
onValueChange = {
value it
}
)
在下面的示例中,当 showCalculation 为真时,Calculation2 Composable 进入组合并传递一个回调命名操作。如果您更改使用新操作回调重组的选择 Calculation2 函数,则会进行计算。如果您记住旧值而不是在延迟结束后更新它 LaunchedEffect 调用过时的操作,这就是您使用 rememberUpdatedState 的原因。因此,虽然函数重组它们接收到的回调可能会发生变化,但您可能需要使用最新的。
/**
* In this example we set a lambda to be invoked after a calculation that takes time to complete
* while calculation running if our lambda gets updated `rememberUpdatedState` makes sure
* that latest lambda is invoked
*/
@Composable
private fun RememberUpdatedStateSample2() {
val context = LocalContext.current
var showCalculation by remember { mutableStateOf(true) }
val radioOptions = listOf("Option?", "Option?", "Option?")
val (selectedOption: String, onOptionsSelected: (String) -> Unit) = remember {
mutableStateOf(radioOptions[0])
}
Column {
radioOptions.forEach { text ->
Column(
modifier = Modifier.selectableGroup()
) {
Row(
Modifier
.selectable(
selected = (text == selectedOption),
onClick = {
if (!showCalculation) {
showCalculation = true
}
onOptionsSelected(text)
},
role = Role.RadioButton
)
.fillMaxWidth()
.padding(vertical = 4.dp)
) {
RadioButton(selected = (text == selectedOption), onClick = null)
Spacer(modifier = Modifier.width(16.dp))
Text(text = text)
}
}
}
Spacer(modifier = Modifier.height(12.dp))
if (showCalculation) {
println("? Invoking calculation2 with option: $selectedOption")
Calculation2 {
showCalculation = false
Toast.makeText(
context,
"Calculation2 $it result: $selectedOption",
Toast.LENGTH_SHORT
)
.show()
}
}
}
}
/**
* LaunchedEffect restarts when one of the key parameters changes.
* However, in some situations you might want to capture a value in your effect that,
* if it changes, you do not want the effect to restart.
* In order to do this, it is required to use rememberUpdatedState to create a reference
* to this value which can be captured and updated. This approach is helpful for effects that
* contain long-lived operations that may be expensive or prohibitive to recreate and restart.
*/
@Composable
private fun Calculation2(operation: (String) -> Unit) {
println("? Calculation2(): operation: $operation")
// This returns the updated operation if we recompose with new operation
val currentOperation by rememberUpdatedState(newValue = operation)
// This one returns the initial operation this Composable enters composition
val rememberedOperation = remember { operation }
// ? This LaunchedEffect block only gets called once, not called on each recomposition
LaunchedEffect(key1 = true, block = {
delay(4000)
currentOperation("rememberUpdatedState")
rememberedOperation("remember")
})
Row(verticalAlignment = Alignment.CenterVertically) {
CircularProgressIndicator(color = getRandomColor())
}
}
您还可以考虑更实际的情况,当您从远程服务器加载数据时,用户可能会像上面的示例那样与您的应用交互,并且您可能需要在加载完成后根据用户的最新交互进行导航。