I'm using the Jetpack Navigation library with the Compose version. 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.
I found a way to do this using Activities here but I want to avoid creating any extra activities and do this in compose.
If you want to use the Navigation component with Compose, you have two options: Define a navigation graph with the Navigation component for fragments. Define a navigation graph with a NavHost in Compose using Compose destinations. This is possible only if all of the screens in the navigation graph are composables.
A LazyColumn is a vertically scrolling list that only composes and lays out the currently visible items. It's similar to a Recyclerview in the classic Android View system.
However, this would mean that virtually none of the built-in ActivityResultContracts could be used with Jetpack Compose. How would an app launch an ActivityResultsContract request from a @Composable function?
I found a way to do this using Activities here but I want to avoid creating any extra activities and do this in compose. The ability to return a result also works in Navigation Compose; it is a core part of Navigation. From the Composable that you want to return data, you can do the following:
The Navigation component provides support for Jetpack Compose applications. You can navigate between composables while taking advantage of the Navigation component’s infrastructure and features. Note: If you are not familiar with Compose, review the Jetpack Compose resources before continuing.
In your fragment, you make the bridge between Compose and the fragment-based Navigation component by finding the NavController and navigating to the destination: Alternatively, you can pass the NavController down your Compose hierarchy. However, exposing simple functions is much more reusable and testable.
From the Composable that you want to return data, you can do the following:
navController.previousBackStackEntry
?.savedStateHandle
?.set("your_key", "your_value")
navController.popBackStack()
and then, from the source Composable, you can listen for changes using a 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)
@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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With