Jetpack Compose将LiveData传递到可组合lambda



我很难理解为什么我观察到的状态值被正确地传递到可组合的lambda中,但没有触发可组合的重新组合。

这是我的设置。

屏幕

@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) }
)
}
}
)
}

MyController

@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) }
)
}

MyViewModel

@HiltViewModel
class MyViewModel @Inject constructor(): ViewModel() {
private val _someValue: Int? = MutableLiveData(null)
val someValue: LiveData<Int?> = _someValue
fun setValue(newValue: Int) {
_someValue.value = newValue
}
}

当我运行这个并看到输出时,日志不会显示更新的someValue

value updated: 0
value updated: 0
value updated: 0

但是,如果我向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) }
)
}
// ..

当我运行这个并看到输出时,日志会显示正确更新的值。

value updated: 0
value updated: 1
value updated: 2

为什么会发生这种情况?有没有什么方法可以将第一个状态值传递给showBottomSheet可组合lambda?

提前谢谢。

我还没有尝试过你的代码,但这看起来像是这个问题中作用域重组的效果。在这个问题中,即使不记得mutableState值也会更新,因为外部作用域没有重新组合。在您的情况下,因为您传递的是值,而不是由于未触发重组而未更新的状态。

为什么没有记忆的可变状态有时有效?

@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) }
)
}
}
)
}

在该代码中,只有showBottomSheet被重新组合,因此作为值的someValue不会更新,因为MyController范围中没有重新组合。

有了这段代码,我假设showBottomSheet是可组合的,因为你可以调用@Composable函数Flow.collectAsState,你正在重新组合里面的所有东西,这就是为什么它用viewModel.someValue的lates值重新组合的原因

showBottomSheet {
val currentValue = viewModel.someValue.observeAsState().value // <-- Note the difference
Log.d("DEBUG", "value updated: $currentValue")
BottomSheetLayout(
someValue = currentValue,
onUpdateClick = { newValue -> viewModel.setValue(newValue) }
)
}

使用代理

这将以与remember API相同的方式将您的值包装到State<T>,因此每次您的值更改时都会导致重新组合。

val someValue by viewModel.someValue.observeAsState()

在您的示例中,由于.value和未调用recomposition,状态立即转换。

Log.d是一个副作用,应该与它的一个处理程序一起使用。

阅读更多关于Jetpack Compose副作用

使用LaunchedEffect或DisposableEffect

@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) }
)
}
}
)
}

每次你的值改变时,效果就会开始

相关内容

  • 没有找到相关文章

最新更新