How to send parameter from Detail Fragment to Parent Fragment and the Parent receive it as the first thing?

42 Views Asked by At

How are you?

Using Jetpack Navigation, I cannot send the parameters from Child Fragment to Parent Fragment as the first information in Parent. The parameters are received according to LiveData. I'm trying to use: findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData and also SharedViewModel with navGraphViewModels.

But since it's LiveData, the return is indetermined. So, sometimes they are called first, sometimes the UI is called first inside OnViewCreated, and after the methods above are called.

I need a way to always receive the parameters as the first thing when return to Parent to be possible to do some conditionals.

Is there a pattern for that? Thank you.

2

There are 2 best solutions below

1
viethoang On

In order to receive the returned data, it is crucial to note that the Lifecycle must be in the RESUME state

Create extensions for the Fragment

fun <T> Fragment.setNavigationResult(key: String, value: T) {
    findNavController().previousBackStackEntry?.savedStateHandle?.set(
        key,
        value
    )
}

fun <T>Fragment.getNavigationResult(@IdRes id: Int, key: String, onResult: (result: T) -> Unit) {
    val navBackStackEntry = findNavController().getBackStackEntry(id) ?: return

    val observer = LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_RESUME
            && navBackStackEntry.savedStateHandle.contains(key)
        ) {
            val result = navBackStackEntry.savedStateHandle.get<T>(key)
            result?.let(onResult)
            navBackStackEntry.savedStateHandle.remove<T>(key)
        }
    }
    navBackStackEntry.lifecycle.addObserver(observer)

    viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_DESTROY) {
            navBackStackEntry.lifecycle.removeObserver(observer)
        }
    })
}

Child fragment

setNavigationResult("data", data)
findNavController().navigateUp()

Parent fragment

findNavController()?.navigate(directions) // Navigate to child
getNavigationResult<Boolean>(R.id.nav_to_child, "data"){
    // Return data here
}

Hope it helps!

0
Alexandre Bianchi On

I discovered that using setFragmentResult and setFragmentResult listener is the best solution because they are the first thing to receive when return from a fragment to the last one.

In the parent fragment, cofify the return, like below:

setFragmentResultListener("RequestKeyA") { requestKey, bundle -> 
    doYourMethod()
} 

In the second fragment, call the follow command to return to the parent.

setFragmentResult("RequestKeyA", bundleOf(key to BundleObjectWithAnyData))

This is the way, using Navigation.