Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 533
Elforama Avatar asked Mar 27 '21 23:03

Elforama


People also ask

How do I use compose navigation?

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.

What is LazyColumn in jetpack compose?

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.

Can activityresultcontracts be used with Jetpack compose?

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?

Is it possible to return a result in navigation compose?

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:

What is the navigation component used for?

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.

How do I connect a navigation component to a compose fragment?

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.


Video Answer


2 Answers

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
}
like image 102
nglauber Avatar answered Oct 23 '22 22:10

nglauber


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
}
like image 29
Evgenii Doikov Avatar answered Oct 23 '22 21:10

Evgenii Doikov