Problems with Android Fragment Back Stack

Problems with Android Fragment back stack


Explanation: on what's going on here?

If we keep in mind that .replace() is equal with .remove().add() that we know by the documentation:

Replace an existing fragment that was added to a container. This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here.

then what's happening is like this (I'm adding numbers to the frag to make it more clear):

// transaction.replace(R.id.detailFragment, frag1);
Transaction.remove(null).add(frag1) // frag1 on view

// transaction.replace(R.id.detailFragment, frag2).addToBackStack(null);
Transaction.remove(frag1).add(frag2).addToBackStack(null) // frag2 on view

// transaction.replace(R.id.detailFragment, frag3);
Transaction.remove(frag2).add(frag3) // frag3 on view

(here all misleading stuff starts to happen)

Remember that .addToBackStack() is saving only transaction not the fragment as itself! So now we have frag3 on the layout:

< press back button >
// System pops the back stack and find the following saved back entry to be reversed:
// [Transaction.remove(frag1).add(frag2)]
// so the system makes that transaction backward!!!
// tries to remove frag2 (is not there, so it ignores) and re-add(frag1)
// make notice that system doesn't realise that there's a frag3 and does nothing with it
// so it still there attached to view
Transaction.remove(null).add(frag1) //frag1, frag3 on view (OVERLAPPING)

// transaction.replace(R.id.detailFragment, frag2).addToBackStack(null);
Transaction.remove(frag3).add(frag2).addToBackStack(null) //frag2 on view

< press back button >
// system makes saved transaction backward
Transaction.remove(frag2).add(frag3) //frag3 on view

< press back button >
// no more entries in BackStack
< app exits >

Possible solution

Consider implementing FragmentManager.BackStackChangedListener to watch for changes in the back stack and apply your logic in onBackStackChanged() methode:

  • Trace a count of transaction;
  • Check particular transaction by name FragmentTransaction.addToBackStack(String name);
  • Etc.

Fragment BackStack doesn't work properly

The issue with the 'back' button in your Toolbar, is that it is not designed for back navigation. The backwards facing arrow in the Toolbar is for 'up' navigation (incredibly confusing at times -- and often shares the same behavior as the device 'back' button). See this link for further explanation:

http://developer.android.com/design/patterns/navigation.html

While there are certainly ways to override 'up' behavior, (e.g., overriding android.R.id.home in the onOptionsItemSelected method), it might make more sense to add a SettingsActivity that manages the SettingsFragment. You can then set the parent Activity of the SettingsActivity to the MainActivity in your manifest. Then both back and up should work the way you want without overriding any standard OS behavior:

http://developer.android.com/training/implementing-navigation/ancestral.html

Hope that helps!

Fragment and BackStack not working properly

try this,
call method .addToBackStack("returnFragment") while loading second fragment and remove it from first transaction.

How to fix fragments backstack issues in android

Create a singleton named NavigationHandler and add the below functions to it:

Function to open MainFragment:

public void openMainFragment(FragmentManager fragmentManager, MainFragment fragment){
String backStackName = fragment.getClass().getSimpleName();
fragmentManager.beginTransaction()
.replace(R.id.fl_main_container, fragment)
.addToBackStack(backStackName)
.commit();
}

Function to open SubFragment:

public void openSubFragment(FragmentManager fragmentManager, SubFragment fragment){
String backStackName = fragment.getClass().getSimpleName();
fragmentManager.popBackStackImmediate(backStackName, POP_BACK_STACK_INCLUSIVE);
fragmentManager.beginTransaction()
.replace(R.id.fl_main_container, fragment)
.addToBackStack(backStackName)
.commit();
}

For backpress:

public void navigateBackBy(AppCompatActivity activity, int numOfFragments){
if(mFragmentManager.getBackStackEntryCount()==1){
activity.finish();
}
else {
int i;
for (i = 0; i < numOfFragments; i++) {
mFragmentManager.popBackStackImmediate();
}
}
}

In your Activity:

  1. Call openMainFragment(...) to open the MainFragment with the list.

  2. While calling your adapter constructor pass FragmentManager as a parameter.

  3. Override onBackPressed() & add call navigateBackBy(this, 1);. This method is useful to go back by any no. of fragments.

Inside your adapter:

  1. On click of an item call openSubFragment(...).

Fragment back stack clearing Issue

The problem you have lies in the way you are dealing with the fragments lifecycle. You want Fragment C to do onCreateView only once (to show the popup), but onCreateView get's called every time the View is created (e.g, every time you call remove on a fragment(replace works pretty much the same, remove + add) and then add it back from backstack with popbackstack).

For your problems there are two solutions:

Cleaner one: instead of showing your popup from onCreateView, call it from onCreate in Fragment C. With this you will guarantee that it only get's called when the fragment instance is created.

Not so clean: Instead of using replace between Fragment C and D transaction, call add, this way when you pop the backstack in Fragment D, Fragment C onCreateView won't be called because the View was never destroyed (never called remove/replace upon).

Back button not working when adding fragment to backstack

Override onBackPressed() into your activity and call this in order to remove current fragment from backstack, since you add it.

if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStackImmediate()
} else {
finish();
}

This will work only when you add fragment to backstack using addToBackStack() method.

When you add a fragment to backstack to keep tracking your back flow and all the previous changes, that instance will be keeped into FragmentManager. When you want to go back to previous fragment, just pop the latest fragment from backstack. If you don't add it to stack, you will not be able to roll back the taken path and all the previous oprations.

Back stack not working properly in Jetpack Navigation

As per the documentation:

  • The app:defaultNavHost="true" attribute ensures that your NavHostFragment intercepts the system Back button. Note that only one NavHost can be the default. If you have multiple hosts in the same layout (two-pane layouts, for example), be sure to specify only one default NavHost.

You are missing that attribute so Navigation is not handling the system back button.

<androidx.fragment.app.FragmentContainerView
android:id="@+id/nave_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:navGraph="@navigation/nav_graph"
app:defaultNavHost="true"
/>


Related Topics



Leave a reply



Submit