将数据传递到 Android Compose 中之前的可组合项

问题描述 投票:0回答:4

我会拿一个简单的样本。

我有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 的生命周期才能使其保持活动状态?活动,...或其他东西。

或者还有其他方法可以做到这一点吗?

android android-jetpack-compose
4个回答
23
投票

如果您使用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
替换为您的数据。


6
投票

假设有两个屏幕。

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"
            ) ?: ""
    }

对我来说非常有效。


1
投票

您的所有撰写组合操作都发生在单个活动视图层次结构中,因此您的 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 管理状态的文档


0
投票

在第二个屏幕中,您可以像这样发送结果:

navController.previousBackStackEntry?.savedStateHandle?.set("result_key", true)

在父屏幕中您可以观察如下结果:

navController.currentBackStackEntry?.savedStateHandle?.getStateFlow("result_key", false)?.collectAsEffect {
        it.takeIf {
            it
        }?.also {
            //do something
        }
}
© www.soinside.com 2019 - 2024. All rights reserved.