Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Architecture Navigation - How to navigate to specific place in Nav Graph building back stack

I have a linear wizard created with Android Arch Navigation and I would like to start it at specific location building back stack as with natural user navigation. So I have tried this deep link building:

Bundle args = new Bundle();
args.putString("myarg", "From Widget");
 new NavDeepLinkBuilder(context)
    .setGraph(R.navigation.mobile_navigation)
    .setDestination(R.id.step_fragment)
    .setArguments(args)
    .createPendingIntent().send(); 

The problem with this approach is that it doesn't build back stack correctly as user will be build navigating Step 1 -> Step 2 -> ... -> Step N It only holds Step 1 -> Step N, i.e. start destination and target destination of navigation graph. This is not what I want.

Second simple approach is to just call multiple times navigate() on navController. But as it seems simple it doesn't work

 protected fun navigateTo(step: Int) {
        val navController = findNavController(R.id.nav_host_fragment)

        if(step >= 0 && step < stepFragments.count()) {
            // go to step-th fragment
            if(navController.currentDestination.id != stepFragments.first()) return

            for(i in 0 until step) {
                navController.navigate(stepFragments[i])
            }
            navController.navigate(stepFragments[step])
        } else if(step == stepFragments.count()) {
            // go to confirm fragment
            navController.navigate(confirmFragment)
        } else {
            throw IndexOutOfBoundsException("Step index is out of wizard bounds!")
        }
    }

It navigates correctly but then the created back stack is odd, i.e. Back button seems to work, but onNavigatedListener listener from

navController.addOnNavigatedListener(this::onNavigatedListener)

is not called correctly. So I cannot listen for fragment changes in wizard. Moreover NavController seems to be break, as consecutive button listener's navController.navigate(actionId) throws error.

java.lang.IllegalArgumentException: navigation destination is unknown to this NavController

UPDATE!

Intercepting onBackPressed() with debugger seems to show that Back Button Press doesn't call navController.popBackStack() and the navController.currentDestination property doesn't change. But inside NavHostFragment the fragment is changing.

like image 967
Michał Ziobro Avatar asked Oct 17 '22 14:10

Michał Ziobro


1 Answers

It seems that this multi-step navController.navigate() works Ok. And fixing of back-stack while pressing Back button to expected behaviour can be achieved by overriding default onBackPressed() behaviour to something like this:

 //region BACK PRESSED - CUSTOM BACK STACK HANDLING
    override fun onBackPressed() {
        if(!findNavController(R.id.nav_host_fragment).popBackStack()) {
            super.onBackPressed()
        }
    }
    //endregion

And for the record

protected fun navigateTo(step: Int) {
        val navController = findNavController(R.id.nav_host_fragment)

        if(step >= 0 && step < stepFragments.count()) {
            // go to step-th fragment
            if(navController.currentDestination.id != stepFragments.first()) return

            for(i in 0 until step) {
                navController.navigate(stepFragments[i])
            }
            navController.navigate(stepFragments[step])
        } else if(step == stepFragments.count()) {
            // go to confirm fragment
            navController.navigate(confirmFragment)
        } else {
            throw IndexOutOfBoundsException("Step index is out of wizard bounds!")
        }
    }
like image 81
Michał Ziobro Avatar answered Oct 21 '22 07:10

Michał Ziobro