android / architecture-components-samples

Samples for Android Architecture Components.
https://d.android.com/arch
Apache License 2.0
23.4k stars 8.29k forks source link

BottomNavigationView. Navigation to destination with deeplink cause to add destination fragment also in first tab #1003

Open AlexMobileStyles opened 3 years ago

AlexMobileStyles commented 3 years ago

Let's say we have a bottom navigation view with 4 tab, we fave a deeplink for fragment in 4 tab, so when navigate with this deeplink, the 4 tab are selected - it's ok, but when after this manually select firts tab the fragment from 4 tab are added also in first tab.

AlexMobileStyles commented 3 years ago

Problem solved my self with this solution i added an custom extenstion for bottom nav view

fun BottomNavigationView.setupWithNavController(navController: NavController?) {
    navController?.let {
        this.setupWithNavController(it)
    }
    this.setOnItemSelectedListener { menuItem ->
        val builder = NavOptions.Builder().setLaunchSingleTop(true).setRestoreState(false)
        val graph = navController?.currentDestination?.parent
        val destination = graph?.findNode(menuItem.itemId)
        if (menuItem.order and Menu.CATEGORY_SECONDARY == 0) {
            navController?.graph?.findStartDestination()?.id?.let {
                builder.setPopUpTo(
                    it,
                    inclusive = false,
                    saveState = true
                )
            }
        }
        val options = builder.build()
        destination?.id?.let { id -> navController.navigate(id, null, options) }
        return@setOnItemSelectedListener true
    }
}

problem was in setRestoreState(true)

catluc commented 3 years ago

Please open a ticket here, otherwise they will not fix it, Google Issue Tracker

KamikX commented 3 years ago

Hello, I used navigation components version 2.4.0-alpha04 and I have same issue, my solution is inspired by @AlexMobileStyles, the main problem is with setPopUpTomethod with saveState = true, btw is issue already reported on Google Issue Tracker?

fun BottomNavigationView.setupWithNavControllerFixed(navController: NavController?) {
    navController?.let {
        this.setupWithNavController(it)
    }

    NavigationUI

    /**
     *  Fixed by 
     *     NavOptions setRestoreState(false) with  setPopUpTo(saveState = true)
     *     or
     *     NavOptions setRestoreState(true) with  setPopUpTo(saveState = false)
     *  
     *  @see [NavigationUI.onNavDestinationSelected]
     */
    this.setOnItemSelectedListener {item->

        val builder = NavOptions.Builder().setLaunchSingleTop(true).setRestoreState(true)
        if (
            navController!!.currentDestination!!.parent!!.findNode(item.itemId)
                    is ActivityNavigator.Destination
        ) {
            builder.setEnterAnim(R.anim.nav_default_enter_anim)
                .setExitAnim(R.anim.nav_default_exit_anim)
                .setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
                .setPopExitAnim(R.anim.nav_default_pop_exit_anim)
        } else {
            builder.setEnterAnim(R.animator.nav_default_enter_anim)
                .setExitAnim(R.animator.nav_default_exit_anim)
                .setPopEnterAnim(R.animator.nav_default_pop_enter_anim)
                .setPopExitAnim(R.animator.nav_default_pop_exit_anim)
        }
        if (item.order and Menu.CATEGORY_SECONDARY == 0) {
            builder.setPopUpTo(
                navController.graph.findStartDestination().id,
                inclusive = false,
                saveState = false
            )
        }
        val options = builder.build()
        return@setOnItemSelectedListener  try {
            // TODO provide proper API instead of using Exceptions as Control-Flow.
            navController.navigate(item.itemId, null, options)
            true
        } catch (e: IllegalArgumentException) {
            false
        }
    }
}
kartik0198 commented 2 years ago

But this solution breaks multiple stack saved states and whenever we select any bottom nav item, start destination opens instead of last fragment that was there (state is not saved) Any other solution? @KamikX @AlexMobileStyles

xanscale commented 2 years ago

I think the situation is significantly worse: the Multiple back stacks is completely broken.

example 1: if I am in a second level of the first tab and I deeplink on tab 2, the first tab stops responding

example 2: if I am in a second level of the first tab, I navigate with a deeplink on tab 2, then click on tab 3 and then click on tab 1, tab 2 is displayed

and much more, all just using AdvancedNavigationSample and navigation component 2.4.0

deeplink created using this code inside About fragment class

view.findViewById<Button>(R.id.deepLink).setOnClickListener {
    findNavController().navigate("http://www.example.com/user/Person 2".toUri())
}
Lime94 commented 2 years ago

Look's like i've found solution I have two fragments (FragmentAand FragmentB) inside BottomNavigationView I use this code for navigating to FragmentB inside FragmentA

                val navOptions: NavOptions = navBuilder
                    .setPopUpTo(
                        R.id.fragmentA,
                        inclusive = false,
                        saveState = true
                    ).build()

                findNavController().navigate("deeplink://to_fragment_b".toUri(), navOptions)

Backstack working, state saving I used version 2.4.2

Lime94 commented 2 years ago

Oh no sorry it isn't working correct(( After changing item, back stack isn't saving((

sergpetrov commented 2 years ago

The issue is in the google issue tracker https://issuetracker.google.com/issues/213131384

dazza5000 commented 1 year ago

@Lime94 try using setRestoreState in your navOptions too

        navOptionsBuilder.setRestoreState(true)
        navController?.graph?.findStartDestination()?.id?.let {
            navOptionsBuilder.setPopUpTo(
                it,
                popUpToInclusive,
                saveState = true
            )
        }

NVM - this still wont fix the backstack if you navigate using deeplinks from a non top-level destination

user98392 commented 5 months ago

The solution is here: https://stackoverflow.com/a/78075344/16041661