Android: Fragments Backstack

How to resume existing Fragment from BackStack

Reading the documentation, there is a way to pop the back stack based on either the transaction name or the id provided by commit. Using the name may be easier since it shouldn't require keeping track of a number that may change and reinforces the "unique back stack entry" logic.

Since you want only one back stack entry per Fragment, make the back state name the Fragment's class name (via getClass().getName()). Then when replacing a Fragment, use the popBackStackImmediate() method. If it returns true, it means there is an instance of the Fragment in the back stack. If not, actually execute the Fragment replacement logic.

private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();

FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);

if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();
}
}

EDIT

The problem is - when i launch A and then B, then press back button, B
is removed and A is resumed. and pressing again back button should
exit the app. But it is showing a blank window and need another press
to close it.

This is because the FragmentTransaction is being added to the back stack to ensure that we can pop the fragments on top later. A quick fix for this is overriding onBackPressed() and finishing the Activity if the back stack contains only 1 Fragment

@Override
public void onBackPressed(){
if (getSupportFragmentManager().getBackStackEntryCount() == 1){
finish();
}
else {
super.onBackPressed();
}
}

Regarding the duplicate back stack entries, your conditional statement that replaces the fragment if it hasn't been popped is clearly different than what my original code snippet's. What you are doing is adding to the back stack regardless of whether or not the back stack was popped.

Something like this should be closer to what you want:

private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
String fragmentTag = backStateName;

FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);

if (!fragmentPopped && manager.findFragmentByTag(fragmentTag) == null){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment, fragmentTag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();
}
}

The conditional was changed a bit since selecting the same fragment while it was visible also caused duplicate entries.

Implementation:

I highly suggest not taking the the updated replaceFragment() method apart like you did in your code. All the logic is contained in this method and moving parts around may cause problems.

This means you should copy the updated replaceFragment() method into your class then change

backStateName = fragmentName.getClass().getName();
fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped) {
ft.replace(R.id.content_frame, fragmentName);
}
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(backStateName);
ft.commit();

so it is simply

replaceFragment (fragmentName);

EDIT #2

To update the drawer when the back stack changes, make a method that accepts in a Fragment and compares the class names. If anything matches, change the title and selection. Also add an OnBackStackChangedListener and have it call your update method if there is a valid Fragment.

For example, in the Activity's onCreate(), add

getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() {

@Override
public void onBackStackChanged() {
Fragment f = getSupportFragmentManager().findFragmentById(R.id.content_frame);
if (f != null){
updateTitleAndDrawer (f);
}

}
});

And the other method:

private void updateTitleAndDrawer (Fragment fragment){
String fragClassName = fragment.getClass().getName();

if (fragClassName.equals(A.class.getName())){
setTitle ("A");
//set selected item position, etc
}
else if (fragClassName.equals(B.class.getName())){
setTitle ("B");
//set selected item position, etc
}
else if (fragClassName.equals(C.class.getName())){
setTitle ("C");
//set selected item position, etc
}
}

Now, whenever the back stack changes, the title and checked position will reflect the visible Fragment.

Android Fragment Back Stack

I am trying with the fragment list ....

Initilize the framents list

  static List<String> fragments = new ArrayList<String>();

Code to fragment change and take in back stack

   String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
//fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
if(!fragments.contains(backStateName)) {

// ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
// ft.setCustomAnimations(R.anim.fade_in, R.anim.fade_out);
ft.replace(R.id.frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();

fragments.add(backStateName);
System.out.println("backStateName" + fragments);
}
else
{

ft.replace(R.id.frame, fragment);
ft.commit();

}

onBackpressed

 @Override
public void onBackPressed() {
if(fragments.size()>0)
{
fragments.remove(fragments.size()-1);
}
super.onBackPressed();
}

for back remove stack

 final android.app.FragmentManager fm = getFragmentManager();

fm.addOnBackStackChangedListener(new android.app.FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {

if (getSupportFragmentManager().getBackStackEntryCount() ==0) {
// dLayout.closeDrawers();
finish();
}
else
{
// dLayout.closeDrawers();

}
}
});

Android: Fragments backStack

If you really want to replace the fragment then use replace() methode instead of doing a remove() and an add().

    FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(..............);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

Don't forget to do the addToBackStack(null) so your previous state will be added to the backstack allowing you to go back with the back button.

See also https://developer.android.com/reference/android/app/FragmentTransaction.html#replace(int, android.app.Fragment, java.lang.String) .

Another good source is http://developer.android.com/guide/components/fragments.html (search for replace() function).

Android peek backstack without popping

The BackStackEntry id and Fragment id have nothing to do with each other.

I have done something similar to what you are doing by using tags. Again, the BackStackEntry tag and Fragment tags have nothing to do with each other; however, by using the same value for both tags you can accomplish your goal.

String tag = ...
FragmentManager fragManager = mActivity.getSupportFragmentManager();
FragmentTransaction transaction = fragManager.beginTransaction();
// tag is associated with fragment
transaction.replace(R.id.fragment_container, mFragment, tag);
// same tag is associated with back stack entry
transaction.addToBackStack(tag);
transaction.commit();

...

int count = fragmentManager.getBackStackEntryCount();
if (count > 0) {
FragmentManager.BackStackEntry topBackStackEntry =
fragmentManager.getBackStackEntryAt(count - 1);
String tag = topBackStackEntry.getName();

if (tag != null) {
Fragment fragment = fragmentManager.findFragmentByTag(tag);
if (fragment != null) {
// we found the fragment
// you can also sanity-check here with fragment.isResumed()
}
}
}

Fragment doesn't register in backstack

When you call changeFragment function, you're passing true as last argument:

changeFragment(
parentFragmentManager, R.id.fragment_inspection_frame_layout,
InspectionDetailsFragment.newInstance(inspection), true
)

In changeFragment function:

if (addToBackStack) fragmentTransaction.addToBackStack(null)

It doesn't get added to backStack. Instead of null i think you should pass String value as the name of the backStack you want to use.

I'm not 100% sure about this. You can read more about fragment transactions from here: https://developer.android.com/guide/fragments/transactions

Change the position of backstack fragment in android?

You can solve this problem by using Stack in your code. And in fragment transaction, you have to use add instead of replacing the fragment. On button B1 press you have to pop fragment F1 from the stack and again you have to push it to the stack. I thought it may be work for you.



Related Topics



Leave a reply



Submit