我会拿一个简单的样本。
我有2个屏幕:屏幕A和屏幕B。从屏幕A,我打开屏幕B。当我将屏幕B返回到屏幕A时,我想将数据传输回屏幕A。
使用 Android Fragment,我可以使用 Shared ViewModel 或 Fragment Result API 来执行此操作。 但对于 Android Compose,Fragment Result Api 不在 Compose 中。使用 Shard ViewModel 时,我必须附加 Shared ViewModel 的生命周期才能使其保持活动状态?活动,...或其他东西。
或者还有其他方法可以做到这一点吗?
如果您使用jetpack导航,则可以通过将数据添加到前一个返回堆栈条目的savedStateHandle来传回数据。 (文档)
屏幕B传回数据:
composable("B") {
ComposableB(
popBackStack = { data ->
// Pass data back to A
navController.previousBackStackEntry
?.savedStateHandle
?.set("key", data)
navController.popBackStack()
}
)
}
屏幕 A 接收数据:
composable("A") { backStackEntry ->
// get data passed back from B
val data: T by backStackEntry
.savedStateHandle
.getLiveData<T>("key")
.observeAsState()
ComposableA(
data = data,
navToB = {
// optional: clear data so LiveData emits
// even if same value is passed again
backStackEntry.savedStateHandle.remove("key")
// navigate ...
}
)
}
将
"key"
替换为唯一字符串,将 T
替换为您的数据类型,将 data
替换为您的数据。
假设有两个屏幕。
1 - FirstScreen 它将接收一些数据并驻留在后台堆栈的底部,用户将通过按后退按钮从第二个屏幕登陆这里。
2 - SecondScreen 它将发送/附加一些要在之前的第一个屏幕上接收的数据。
让我们从第二个屏幕发送数据开始,为此你可以这样做:
navController.previousBackStackEntry
?.savedStateHandle
?.set("key", viewModel.getFilterSelection().toString())
navController.popBackStack()
现在让我们在第一个屏幕上捕获该数据,这样你就可以做这样的事情:
if (navController.currentBackStackEntry!!.savedStateHandle.contains("key")) {
val keyData =
navController.currentBackStackEntry!!.savedStateHandle.get<String>(
"key"
) ?: ""
}
对我来说非常有效。
您的所有撰写组合操作都发生在单个活动视图层次结构中,因此您的 ViewModel 生命周期将不可避免地绑定到该根活动。实际上可以通过
LocalLifecycleOwner.current
从您的作文中访问它。
请记住,Compose 是一个与 Activity/fragment 完全不同的范式,您确实可以跨可组合项共享 ViewModel,但为了保持简单,您也可以仅通过使用可变值传递状态并触发来“共享”数据重组.
class MySharedViewModel(...) : ViewModel() {
var sharedState by mutableStateOf<Boolean>(...)
}
@Composable
fun MySharedViewModel(viewModel: MySharedViewModel = viewModel()) {
// guessing you already have your own screen display logic
// This also works with compose-navigator
ComposableA(stateResult = viewModel.sharedState)
ComposableB(onUpdate = { viewModel.sharedState = false })
}
fun ComposableA(stateResult: Boolean) {
....
}
fun ComposableB(onUpdate: () -> Unit) {
Button(onClick = { onUpdate() }) {
Text("Update ComposableA result")
}
}
在这里您可以找到更多有关使用 compose 管理状态的文档
在第二个屏幕中,您可以像这样发送结果:
navController.previousBackStackEntry?.savedStateHandle?.set("result_key", true)
在父屏幕中您可以观察如下结果:
navController.currentBackStackEntry?.savedStateHandle?.getStateFlow("result_key", false)?.collectAsEffect {
it.takeIf {
it
}?.also {
//do something
}
}