[英]Jetpack Compose passing LiveData to a Composable lambda
I'm having trouble understanding why my value I'm observing as state is properly passed into a Composable lambda, but does not trigger that composable to recompose.我无法理解为什么我观察到我的值,因为 state 已正确传递到可组合 lambda 中,但不会触发可组合重构。
Here's my setup.这是我的设置。
@Composable
fun Screen(
showBottomSheet: (@Composable () -> Unit) -> Unit,
viewModel: MyViewModel = hiltViewModel()
) {
val someValue = viewModel.someValue.observeAsState().value
MyController(
onShowBottomSheetClick = {
showBottomSheet {
Log.d("DEBUG", "value updated: $someValue")
BottomSheetLayout(
someValue = someValue,
onUpdateClick = { newValue -> viewModel.setValue(newValue) }
)
}
}
)
}
@Composable
fun MyController(
onShowBottomSheetClick: () -> Unit
) {
Text(
text = "show BottomSheet",
modifier = Modifier.clickable { onShowBottomSheetClick() }
)
}
@Composable
fun BottomSheetLayout(
someValue: Int,
onUpdateClick: (Int) -> Unit
) {
Text(
text = "Some value: $someValue",
modifier = Modifier.clickable { onUpdateClick(someValue + 1) }
)
}
@HiltViewModel
class MyViewModel @Inject constructor(): ViewModel() {
private val _someValue: Int? = MutableLiveData(null)
val someValue: LiveData<Int?> = _someValue
fun setValue(newValue: Int) {
_someValue.value = newValue
}
}
When I run this and see output, the log doesn't show updated someValue
.当我运行它并看到 output 时,日志没有显示更新的
someValue
。
value updated: 0
value updated: 0
value updated: 0
However, if I add a new state value to the lambda itself, it work fine.但是,如果我将新的 state 值添加到 lambda 本身,它就可以正常工作。
// Screen
// ..
showBottomSheet {
val currentValue = viewModel.someValue.observeAsState().value // <-- Note the difference
Log.d("DEBUG", "value updated: $currentValue")
BottomSheetLayout(
someValue = currentValue,
onUpdateClick = { newValue -> viewModel.setValue(newValue) }
)
}
// ..
When I run this and see output, the log shows properly updated value.当我运行它并看到 output 时,日志显示正确更新的值。
value updated: 0
value updated: 1
value updated: 2
Why is this happening?为什么会这样? Is there any way I can pass the first state value to the
showBottomSheet
composable lambda?有什么办法可以将第一个 state 值传递给
showBottomSheet
可组合 lambda?
Thank you in advance.先感谢您。
Log.d is a Side-Effect and should be used with one of its handler. Log.d 是一个副作用,应该与它的一个处理程序一起使用。
read more about Jetpack Compose Side-Effects 阅读有关 Jetpack Compose 副作用的更多信息
@Composable
fun Screen(
showBottomSheet: (@Composable () -> Unit) -> Unit,
viewModel: MyViewModel = hiltViewModel()
) {
val someValue = viewModel.someValue.observeAsState().value
LaunchedEffect(someValue) {
Log.d("DEBUG", "value updated: $someValue")
}
MyController(
onShowBottomSheetClick = {
showBottomSheet {
BottomSheetLayout(
someValue = someValue,
onUpdateClick = { newValue -> viewModel.setValue(newValue) }
)
}
}
)
}
I haven't tried your code but this looks like an effect of scoped recomposition as in this question.我没有尝试过你的代码,但这看起来像是这个问题中范围重组的效果。 In that question even without remember mutableState value is updated because outer scope wasn't recomposed.
在那个问题中,即使没有记住 mutableState 值也会更新,因为外部 scope 没有重组。 In your case since you are passing value instead of state that is not updated because of not triggering recomposition.
在您的情况下,因为您传递的是 value 而不是 state 因为没有触发重组而没有更新。
Why does mutableStateOf without remember work sometimes? 为什么没有记忆的 mutableStateOf 有时会起作用?
@Composable
fun Screen(
showBottomSheet: (@Composable () -> Unit) -> Unit,
viewModel: MyViewModel = hiltViewModel()
) {
val someValue = viewModel.someValue.observeAsState().value
MyController(
onShowBottomSheetClick = {
showBottomSheet {
Log.d("DEBUG", "value updated: $someValue")
BottomSheetLayout(
someValue = someValue,
onUpdateClick = { newValue -> viewModel.setValue(newValue) }
)
}
}
)
}
In this code only showBottomSheet
is recomposed and because of that someValue which is a value is not updated since there is no recomposition in MyController
scope.在此代码中,仅重构了
showBottomSheet
,并且由于MyController
scope 中没有重构,因此作为值的 someValue 未更新。
With this code, i assume showBottomSheet
is a Composable since you are able to call @Composable function Flow.collectAsState you are recomposing everything inside and that's why it's recomposed with lates value of viewModel.someValue
使用此代码,我假设
showBottomSheet
是可组合的,因为您可以调用 @Composable function Flow.collectAsState 您正在重新组合内部的所有内容,这就是为什么它使用viewModel.someValue
的最新值重新组合
showBottomSheet {
val currentValue = viewModel.someValue.observeAsState().value // <-- Note the difference
Log.d("DEBUG", "value updated: $currentValue")
BottomSheetLayout(
someValue = currentValue,
onUpdateClick = { newValue -> viewModel.setValue(newValue) }
)
}
That wraps your value to State<T>
the same way as remember API
does, thus recomposition will be caused every time your value changes.这将您的值包装到
State<T>
与remember API
的方式相同,因此每次您的值更改时都会导致重新组合。
val someValue by viewModel.someValue.observeAsState()
In your example the state immediately transformed because of .value
and recomposition was not called.在您的示例中,state 由于
.value
而立即转换,并且未调用重组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.