17

I am using Navigation component. when navigating I want to not create new instance of fragment if it already exists in backstack and pop that already existing in front.

    findNavController().navigate(RequestTransferFragmentDirections.actionRequestTransferFragmentToBlankFragment())

looking fowrard to find solution.

thanks.

  • Please add some more detail about what you're asking. Add some code to show what you've programmed or add a picture that could be useful. That way you are way more likely to get an answer to your question. – Daan Seuntjens Mar 30 '20 at 09:21
  • I added the code. if it is not enough tell me what code should I add. – Aleksadnre Bibilashvili Mar 30 '20 at 11:19
  • Hello did you find if there is a way to add one instance of the fragment? – Alan Deep May 14 '20 at 18:11
  • 1
    Hello, yes i geuss I override fun onNavigationItemSelected(item: MenuItem): Boolean in Main activity and used navOptions. val navBuilder = NavOptions.Builder() val navOptions = navBuilder.setPopUpTo(item.itemId, true).build() – Aleksadnre Bibilashvili Jul 09 '20 at 10:37

4 Answers4

8

I faced the same problem, but the previous solutions didn't work for me unfortunately, in spite of they are supposed to fix the issue. Thanks btw! :)

This worked for me, adapted to your code would be:

findNavController().navigate(
    RequestTransferFragmentDirections.actionRequestTransferFragmentToBlankFragment()),
    NavOptions.Builder().setLaunchSingleTop(true).build()
)

I saw in the navigate() documentation that we can pass options, so by passing NavOptions.Builder().setLaunchSingleTop(true).build() will create a single instance of such fragment.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Miguel Garcia
  • 1,389
  • 16
  • 16
5

Answering here because I had the same question. The following is a solution that worked for me. I ended up using the nav controller and popping to a backstack destination if it exists, if it doesn't exist then I navigate to it normally.

This looks like this:

if ( ! nav.popBackStack(R.id.action_profile, false)) {
    nav.navigate(R.id.action_profile)
}

nav.popBackStack(R.id.action_profile, false) will return false if the destination passed in is not in the backstack, otherwise it pops to it and returns true if it is. The boolean is used to pop the destination fragment as well.

From the docs:

/**
     * Attempts to pop the controller's back stack back to a specific destination.
     *
     * @param destinationId The topmost destination to retain
     * @param inclusive Whether the given destination should also be popped.
     *
     * @return true if the stack was popped at least once and the user has been navigated to
     * another destination, false otherwise
     */
    public boolean popBackStack(@IdRes int destinationId, boolean inclusive) {
        boolean popped = popBackStackInternal(destinationId, inclusive);
        // Only return true if the pop succeeded and we've dispatched
        // the change to a new destination
        return popped && dispatchOnDestinationChanged();
    }

Lighterletter
  • 209
  • 2
  • 13
4

I implemented the request of only one instance of a fragment type in this mode:

in navigation_graph.xml I declared a popUp-action to the fragment-destination

<action
    android:id="@+id/home_action"
    app:destination="@id/my_dest"
    app:popUpTo="@id/my_dest"
    app:popUpToInclusive="true" />

<fragment
    android:id="@+id/my_dest"
    android:name="com.project.android.fragments.MyFragment"
    android:label=""
    tools:layout="@layout/my_fragment_layout" />

In code I call the action

navController.navigate(R.id.home_action)
Nena Schmidt
  • 174
  • 2
  • 3
  • It worked for me. Thanks. This explanation helped me to understand better these action options: https://stackoverflow.com/a/70143987/1935135 – André Luiz Reis Feb 02 '23 at 20:39
2

You can do something like:

bottomNavigation.setupWithNavController(navController)
bottomNavigation.setOnNavigationItemSelectedListener {
    if (it.itemId == R.id.navigation_home) {
        navController.popBackStack(R.id.navigation_home, false)
        true
    }
    else
        NavigationUI.onNavDestinationSelected(it , navController)
}

enter image description here

With the code above whenever the user clicks on the Home (R.id.navigation_home) item in the bottom navigation view, the app will navigate back to the existing instance of the Home destination using the popBackStack().

If the selects another destination in the bottom navigation, the app will navigates to that destination using NavigationUI.onNavDestinationSelected()