简体   繁体   English

Jetpack Compose 导航结果

[英]Jetpack Compose navigate for result

I'm using the Jetpack Navigation library with the Compose version.我在 Compose 版本中使用 Jetpack Navigation 库。 I'm setting up navigation like it's shown here我正在设置导航,就像这里显示的那样

I want to be able to navigate from screen A to screen B. Once B does something and pops off the back stack, it will then return a result that screen A can access.我希望能够从屏幕 A 导航到屏幕 B。一旦 B 执行某些操作并弹出返回堆栈,它将返回屏幕 A 可以访问的结果。

I found a way to do this using Activities here but I want to avoid creating any extra activities and do this in compose.我找到了一种使用 Activities here来执行此操作的方法,但我想避免创建任何额外的 Activity 并在 compose 中执行此操作。

From the Composable that you want to return data, you can do the following:从要返回数据的 Composable 中,您可以执行以下操作:

navController.previousBackStackEntry
    ?.savedStateHandle
    ?.set("your_key", "your_value")
navController.popBackStack()

and then, from the source Composable, you can listen for changes using a LiveData .然后,从源 Composable 中,您可以使用LiveData监听更改。

val secondScreenResult = navController.currentBackStackEntry
    ?.savedStateHandle
    ?.getLiveData<String>("your_key")?.observeAsState()
...
secondScreenResult?.value?.let {
    // Read the result
}

If you need only once get value, you need remove value after usage:如果您只需要一次获取值,则需要在使用后删除值:

val screenResultState = navController.currentBackStackEntry
    ?.savedStateHandle
    ?.getLiveData<String>("some_key")?.observeAsState()

screenResultState?.value?.let {
    ...
    // make something, for example `viewModel.onResult(it)`
    ...
    //removing used value
    navController.currentBackStackEntry
        ?.savedStateHandle
        ?.remove<String>("some_key")
}

I also extract it in function (for JetPack Compose)我还在 function 中提取它(用于 JetPack Compose)

@Composable
fun <T> NavController.GetOnceResult(keyResult: String, onResult: (T) -> Unit){
    val valueScreenResult =  currentBackStackEntry
        ?.savedStateHandle
        ?.getLiveData<T>(keyResult)?.observeAsState()

    valueScreenResult?.value?.let {
        onResult(it)
       
        currentBackStackEntry
            ?.savedStateHandle
            ?.remove<T>(keyResult)
    }
}

you can copy it to your project and use like this:您可以将其复制到您的项目中并像这样使用:

navController.GetOnceResult<String>("some_key"){
    ...
    // make something
}

for jetpack compose you must use Flow with collectAsState for get result:对于 jetpack compose,您必须将FlowcollectAsState一起使用以获得结果:

navController.currentBackStackEntry
?.savedStateHandle?.getStateFlow<Boolean?>("refresh", false)
?.collectAsState()?.value?.let {
if (it)screenVM.refresh() }

also you can remove Entry with add this after screenVM.refresh() :你也可以在screenVM.refresh()之后添加这个来删除条目:

 navController.currentBackStackEntry
                ?.savedStateHandle ?.set("refresh", false)

You can get the result without a LiveData or a Flow, you can use savedStateHandle.remove method.您可以在没有 LiveData 或 Flow 的情况下获得结果,您可以使用savedStateHandle.remove方法。 I think this is the easier way:我认为这是更简单的方法:

val secondResult = appNavController.currentBackStackEntry?.savedStateHandle?.remove<Data?>("data")
secondResult?.let { data ->
    Log.d(TAG, "Data result: $data")
}

add dependency添加依赖

implementation "androidx.compose.runtime:runtime-livedata:$compose_version"

On the Sender screen set a key value pair to send back to the caller screen, I use a Boolean with key name of "key" value true在发件人屏幕上设置一个键值对发送回调用者屏幕,我使用 Boolean 键名称为“key”值 true

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

navigate up向上导航

navController.navigateUp()

The receiver screen (caller) listens to the results and then remove it:接收者屏幕(调用者)听取结果,然后将其删除:

 val result =  navController.currentBackStackEntry?.savedStateHandle
    ?.getLiveData<Boolean>("key")?.observeAsState()
result?.value?.let {
    navController.currentBackStackEntry?.savedStateHandle
        ?.remove<Boolean>("key")
}

First Screen第一屏

@Composable fun FirstScreen(navController: NavController){

val result =  navController.currentBackStackEntry?.savedStateHandle
    ?.getLiveData<Boolean>("key")?.observeAsState()
result?.value?.let {
    navController.currentBackStackEntry?.savedStateHandle
        ?.remove<Boolean>("key")
}

Button(onClick = {
    navController.navigateUp("secondScreen")
}) {
    "Open second screen"
}}
val navController = rememberNavController()
composable("A") {
    val viewmodel: AViewModel = hiltViewModel()
    AScreen()
}
composable("B") {
    val viewmodel: BViewModel = hiltViewModel()
    val previousViewmodel: AViewModel? = navController
        .previousBackStackEntry?.let {
            hiltViewModel(it)
        }
    BScreen(
       back = { navController.navigateUp() },
       backWhitResult = { arg ->
           previousViewmodel?.something(arg)
       }
    )
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM