'Jetpack Compose navigate for result
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.
Solution 1:[1]
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
}
Solution 2:[2]
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
}
Solution 3:[3]
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)
}
)
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | nglauber |
Solution 2 | |
Solution 3 | CTD |