Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create only one instance of fragment while navigating to destinations(android)

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.

like image 439
Aleksadnre Bibilashvili Avatar asked Mar 30 '20 09:03

Aleksadnre Bibilashvili


4 Answers

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();
    }

like image 150
Lighterletter Avatar answered Oct 18 '22 06:10

Lighterletter


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()

like image 33
ZakariaBK Avatar answered Sep 22 '22 13:09

ZakariaBK


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.

like image 6
Miguel Garcia Avatar answered Oct 18 '22 07:10

Miguel Garcia


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)
like image 4
Nena Schmidt Avatar answered Oct 18 '22 06:10

Nena Schmidt