2

This case might be a unique one because I do have some complicated navigation logic and I'm using extension functions(which I will share below shortly).

  • Imagine having a Fragment(A) opening a BottomSheetFragment(B)
  • And the BottomSheetFragment(B) has a button inside.
  • Tapping on the button dismisses the BottomSheetFragment(B) and navigates to a new Fragment(C).

To handle this case, I'm using 2 extension functions:

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

fun <T> Fragment.getNavigationResult(key: String) = findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<T>(key)

Implementation of setNavigationResult in BottomSheetFragment(B)

loginButton.setOnClickListener {
            dismiss()
            setNavigationResult(EVENT_CUSTOMER_SIGNUP_LOGIN, Event(true))
        }

Implementation of getNavigationResult in Fragment(A)

getNavigationResult<Event<Boolean>>(EVENT_CUSTOMER_SIGNUP_LOGIN)?.observe(viewLifecycleOwner) { event ->
            event.value?.let {
                findNavController().navigate(R.id.openCustomerLogin)
            }
        }

The application crashes with the below error:

    java.lang.IllegalArgumentException: Navigation action/destination openFragmentC cannot be found from the current destination Destination(FragmentB)

What I don't understand here is, the current destination is still BottomSheetFragment(B) even I called dismiss before.

When I add a delay before navigating to FragmentC, then the application does not crash.

lifecycleScope.launch {
                    delay(250)
                    findNavController().navigate(R.id.openCustomerLogin)
                }

I don't like the solution with delay, because it's not practical and can easily be forgotten in new implementations.

Sorry for the long post, I will appreciate it if you share your thoughts on this and assist me.

Aydinozkan
  • 2,508
  • 2
  • 21
  • 26

1 Answers1

0

I have implemented like below

suppose below code for bottomsheet while click on button

 private fun closeBottomSheet() {
        findNavController().previousBackStackEntry?.savedStateHandle?.set("refresh", true)
        findNavController().navigateUp()
    }

and below code for fragment A

val observer = LifecycleEventObserver { _, event ->
            if (event == Lifecycle.Event.ON_RESUME
                && navBackStackEntry.savedStateHandle.contains("refresh")
            ) {
                val result = navBackStackEntry.savedStateHandle.get<Boolean>("refresh")
                if (result!!) {
                    result.run {
                        // whatever you do , go from fragment A to Fragment C
                        navBackStackEntry.savedStateHandle.remove<Boolean>("refresh")
                    }
                }
            }
        }
    

And also check you have define action in fragment A in navigation.xml

gaurav gupta
  • 513
  • 1
  • 6
  • 13
  • Hi gaurav gupta, I tried with findNavController().navigateUp() instead of dismiss. It still crashes without delay(250). Fragment A has the definition to navigate to Fragment C, but FragmentB does not. – Aydinozkan Aug 12 '21 at 08:39
  • if result is null, your app would crash in this instance, I would not use the code like that. You should instead do `result?.run { ... }` – Martin Marconcini Aug 12 '21 at 09:19
  • In case of null or not null you write code like this result?.let { result -> // whatever you do } – gaurav gupta Aug 12 '21 at 09:43