I ported my Android app to honeycomb and I did a big refactor in order to use fragments. In my previous version, when I pressed the Home button I used to do a ACTIVITY_CLEAR_TOP in order to reset the back stack.
Now my app is just a single Activity with multiple fragments, so when I press the Home button I just replace one of the fragments inside it. How can I clear my back stack without having to use startActivity with the ACTIVITY_CLEAR_TOP flag?
I posted something similar here
From Joachim's answer, from Dianne Hackborn:
http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42
I ended up just using:
FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
fm.popBackStack();
}
But could equally have used something like:
((AppCompatActivity)getContext()).getSupportFragmentManager().popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)
Which will pop all states up to the named one. You can then just replace the fragment with what you want
To make an answer for #Warpzit's comment and make it easier for others to find.
Use:
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
With all due respect to all involved parties; I'm very surprised to see how many of you could clear the entire fragment back stack with a simple
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
According to Android documentation (regarding the name argument - the "null" in the claimed working proposals).
If null, only the top state is popped
Now, I do realize that I'm lacking knowledge of your particular implementations (like how many entries you have in the back stack at the given point in time), but I would bet all my money on the accepted answer when expecting a well defined behaviour over a wider range of devices and vendors:
(for reference, something along with this)
FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
fm.popBackStack();
}
Clear backstack without loops
String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Where name is the addToBackStack() parameter
getSupportFragmentManager().beginTransaction().
.replace(R.id.container, fragments.get(titleCode))
.addToBackStack(name)
Works for me and easy way without using loop:
FragmentManager fragmentManager = getSupportFragmentManager();
//this will clear the back stack and displays no animation on the screen
fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Accepted answer was not enough for me. I had to use :
FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
fm.popBackStackImmediate();
}
Hi~I found a solution which is much better,from: https://gist.github.com/ikew0ng/8297033
/**
* Remove all entries from the backStack of this fragmentManager.
*
* #param fragmentManager the fragmentManager to clear.
*/
private void clearBackStack(FragmentManager fragmentManager) {
if (fragmentManager.getBackStackEntryCount() > 0) {
FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
fragmentManager.popBackStack(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
I just wanted to add :--
Popping out from backstack using following
fragmentManager.popBackStack()
is just about removing the fragments from the transaction, no way it is going to remove the fragment from the screen.
So ideally, it may not be visible to you but there may be two or three fragments stacked over each other, and on back key press the UI may look cluttered,stacked.
Just taking a simple example:-
Suppose you have a fragmentA which loads Fragmnet B using fragmentmanager.replace() and then we do addToBackStack, to save this transaction.
So the flow is :--
STEP 1 -> FragmentA->FragmentB (we moved to FragmentB, but Fragment A is in background, not visible).
Now You do some work in fragmentB and press the Save button—which after saving should go back to fragmentA.
STEP 2-> On save of FragmentB, we go back to FragmentA.
STEP 3 ->So common mistake would be... in Fragment B,we will do fragment Manager.replace() fragmentB with fragmentA.
But what actually is happenening, we are loading Fragment A again, replacing FragmentB . So now there are two FragmentA (one from STEP-1, and one from this STEP-3).
Two instances of FragmentsA are stacked over each other, which may not be visible , but it is there.
So even if we do clear the backstack by above methods, the transaction is cleared but not the actual fragments.
So ideally in such a particular case, on press of save button you simply need to go back to fragmentA by simply doing fm.popBackStack() or fm.popBackImmediate().
So correct Step3-> fm.popBackStack() go back to fragmentA, which is already in memory.
For the kotlin people around here:
repeat(supportFragmentManager.backStackEntryCount) {
supportFragmentManager.popBackStack()
}
Reading the documentation and studying what the fragment id is, it appears to simply be the stack index, so this works:
fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Zero (0) is the the bottom of the stack, so popping up to it inclusive clears the stack.
CAVEAT: Although the above works in my program, I hesitate a bit because the FragmentManager documentation never actually states that the id is the stack index. It makes sense that it would be, and all my debug logs bare out that it is, but perhaps in some special circumstance it would not? Can any one confirm this one way or the other? If it is, then the above is the best solution. If not, this is the alternative:
while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }
Just use this method and pass Context & Fragment tag upto which we need to remove the backstake fragments.
Usage
clearFragmentByTag(context, FragmentName.class.getName());
public static void clearFragmentByTag(Context context, String tag) {
try {
FragmentManager fm = ((AppCompatActivity) context).getSupportFragmentManager();
for (int i = fm.getBackStackEntryCount() - 1; i >= 0; i--) {
String backEntry = fm.getBackStackEntryAt(i).getName();
if (backEntry.equals(tag)) {
break;
} else {
fm.popBackStack();
}
}
} catch (Exception e) {
System.out.print("!====Popbackstack error : " + e);
e.printStackTrace();
}
}
It is working for me,try this one:
public void clearFragmentBackStack() {
FragmentManager fm = getSupportFragmentManager();
for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
fm.popBackStack();
}
}
I got this working this way:
public void showHome() {
getHandler().post(new Runnable() {
#Override
public void run() {
final FragmentManager fm = getSupportFragmentManager();
while (fm.getBackStackEntryCount() > 0) {
fm.popBackStackImmediate();
}
}
});
}
private void clearBackStack(){
SupportFragmentManaer fm = getSupportFragmentManager();
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
Call to this method would be very neat.
No Loop required.
If you are using animation in fragments, it will not show too many animations. But using loop will.
private boolean removeFragFromBackStack() {
try {
FragmentManager manager = getSupportFragmentManager();
List<Fragment> fragsList = manager.getFragments();
if (fragsList.size() == 0) {
return true;
}
manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
Related
how I can pop specific fragment from stack and remove others from a fragment?
for example these are my fragments and I'm in E right know.
A-> B -> C -> D ->E
wanna back from E to B and Clear C and D.
How I can do this?
You can add a tag to each fragment while adding them to the backstack and then popfragment from backstack till the fragment with the tag you want is not reached.
FragmentManager fm = getFragmentManager();
for (int i = fm.getBackStackEntryCount() - 1; i > 0; i--) {
if (!fm.getBackStackEntryAt(i).getName().equalsIgnoreCase(tagname)) {
fm.popBackStack();
}
else
{
break;
}
}
You can call the function below while you are in Fragment E:
getFragmentManager().popBackStack("tag", 0);
Here the tag is string passed as tag while adding fragment B to backstack.
If you are using AndroidX navigation, you can use the following:
findNavController().popBackStack(R.id.FragmentB, false)
Use following code for pop back stack entry:
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
fm.popBackStack();
}else {
super.onBackPressed();
}
tldr: try using fragmentManager instead of supportFragmentManager if the code doesn't work
solution: fragmentManager.popBackStackImmediate(tagName, 0)
I know it's an old question but after spending a few hours on this, I wasn't able to get close to the desired result.
I was using supportFragmentManager and the code was:
supportFragmentManager.popBackStackImmediate(tagName, 0)
but it wasn't working as intended neither according to what was written in the documentation.
Just as a fluke I thought about using the fragmentManager instead of the supportFragmentManager and voila, it worked!
So for anyone stuck on this, maybe give this a try.
I am developing an application which is based on Fragment and main activity implements the Slide navigation. I have got three fragment."A", "B", "C" Let say I traverse from "B" fragment to an independent activity. When I try to return from Activity, it lands me up on "A" Fragment where as I want to return to same fragment from where I traversed to activity.
I am using the below code to transact with Fragments
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container_body, fragment);
fragmentTransaction.commit();
}
How to do this?
check it out my below code,
#Override
public void onBackPressed() {
super.onBackPressed();
FragmentManager fm = getSupportFragmentManager();
if (fm.getBackStackEntryCount() == 1) {
//your code goes here
} else if (fm.getBackStackEntryCount() > 1) {
fm.popBackStack();
//your code goes here
} else {
fm.popBackStack();
//your code goes here
}
}
count return number of fragment you have crossed, comment it if you need any help
The problem you're dealing with pretty common in Android and they've explained in a good article in the docs.
So basically, you want to use the BackStack but for your specific issue, there is another solution: when you're moving to the other activity, the original one (which contains B) is basically not destroyed so, what you could do is put states in this activity (the one containing A, B and C) and, as soon as, you come back from your independant activity, your onResume will be fired and you just have to override it to make it display the fragment you want.
Currently I have one activity, and fragments are being added to it (search, song details, settings, etc). I implemented side based menu navigation, so now, as a side effect, tehre's no limit to how many Fragments get added to the Backstack. Is there any way I can limit the number of fragments, or remove older entries? Each song details fragment for instance, has a recommended song list, and through that you can go to another song details fragment. It's easily possible to have 30 fragments in the backstack, which if you have DDMS open, you can see the heap size slowly (but surely) increasing.
Edit: One thing I did try to do is if a User clicked one of the side menu options, if that fragment is already in the backstack try to go back to that fragment instead of instantiating a new one, but of course, if a user is on a Song Details page, then he would expect pressing back would take him to that Fragment so that won't work.
Edit 2:
This is my addFragment method (along with Phil's suggestion):
public void addFragment(Fragment fragment) {
FragmentManager fm = getSupportFragmentManager();
if(fm.getBackStackEntryCount() > 2) {
fm.popBackStack();
}
fm.beginTransaction()
.replace(R.id.fragment_container, fragment).addToBackStack("")
.commit();
}
I just tried it, and assuming my Fragment history is: A->B->C->D, going back from D, goes B->A->exit.
I just went 8 levels deep to test: A->B->C->D->E->F->G->H, and going back from H, same thing happened: H->B->A->exit.
All Fragments are getting added through that method above. What I would like to see is: H->G->F->exit.
You can programatically control the number of Fragments in your BackStack:
FragmentManager fm = getActivity().getSupportFragmentManager();
if(fm.getBackStackEntryCount() > 10) {
fm.popBackStack(); // remove one (you can also remove more)
}
Simply check how many Fragments there are in your Backstack and remove if there is an "overflow".
If you want to remove specific Fragments from the BackStack, you will have to implement your own BackStack and override onBackPressed(). Since the Fragment BackStack is a Stack (as the name indicates), only the top element (the last added) can be removed, there is no possibility of removing Fragments in between.
You could for example use
ArrayList<Fragment>
to realize your own stack. Simply add and remove Fragments from that "stack" (it's not really a stack anymore) whenever you desire and handle the loading of previous fragments by overriding the onBackPressed() method.
This is an old question but my answer might help someone.
Why not checking if the fragment is in the stack and pop it? This way you wouldn't have to worry with back stack size (unless you have a lot of fragments).
String backStateName = fragment.getClass().getName();
boolean fragmentPopped = false;
try {
// true if fragment is in the stack
fragmentPopped = fragmentManager.popBackStackImmediate(backStateName, 0);
} catch (Exception e) {
e.printStackTrace();
}
FragmentTransaction ft = fragmentManager.beginTransaction();
if ( !fragmentPopped ) { //fragment not in back stack, add it...
ft.setTransition( FragmentTransaction.TRANSIT_FRAGMENT_FADE );
ft.replace(R.id.main, fragment);
ft.addToBackStack( backStateName );
try {
ft.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
hi how to clear fragment back stack am using below logic it's not working...
for(int i = 0; i < mFragmentManager.getBackStackEntryCount(); ++i) {
mFragmentManager.popBackStack();
}
help me..
Try this
mFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Answer above is almost correct, but you need a guard around the fragment back list as it can be empty:
private void clearBackStack() {
FragmentManager manager = getSupportFragmentManager();
if (manager.getBackStackEntryCount() > 0) {
FragmentManager.BackStackEntry first = manager.getBackStackEntryAt(0);
manager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
while (getSupportFragmentManager().getBackStackEntryCount() > 0){
getSupportFragmentManager().popBackStackImmediate();
}
one way is to tag the backstack and when you want to clear it
mFragmentManager.popBackStack("myfancyname", FragmentManager.POP_BACK_STACK_INCLUSIVE);
where the "myfancyname" should match the string you used with addToBackStack. E.g.
Fragment fancyFragment = new FancyFragment();
fragmentTransaction.replace(R.id.content_container, fancyFragment, "myfragmentag");
fragmentTransaction.addToBackStack("myfancyname");
the backstack's name and the fragment's tag name can be the same but there are no constrains on this regard
From the documentation
If set, and the name or ID of a back stack entry has been supplied,
then all matching entries will be consumed until one that doesn't
match is found or the bottom of the stack is reached. Otherwise, all
entries up to but not including that entry will be removed.
if you don't want to use a name for your backstack you can pass use a first parameter
mFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
This is a bit late but I just had this problem myself. You can do:
FragmentManager manager = getFragmentManager();
FragmentManager.BackStackEntry first = manager.getBackStackEntryAt(0);
manager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
Pretty self explanatory; you just get the first entry, get its id, and then pop everything up to and including the entry with that id.
The best option I ever seen is here.
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count > 0) {
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
I ported my Android app to honeycomb and I did a big refactor in order to use fragments. In my previous version, when I pressed the Home button I used to do a ACTIVITY_CLEAR_TOP in order to reset the back stack.
Now my app is just a single Activity with multiple fragments, so when I press the Home button I just replace one of the fragments inside it. How can I clear my back stack without having to use startActivity with the ACTIVITY_CLEAR_TOP flag?
I posted something similar here
From Joachim's answer, from Dianne Hackborn:
http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42
I ended up just using:
FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
fm.popBackStack();
}
But could equally have used something like:
((AppCompatActivity)getContext()).getSupportFragmentManager().popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)
Which will pop all states up to the named one. You can then just replace the fragment with what you want
To make an answer for #Warpzit's comment and make it easier for others to find.
Use:
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
With all due respect to all involved parties; I'm very surprised to see how many of you could clear the entire fragment back stack with a simple
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
According to Android documentation (regarding the name argument - the "null" in the claimed working proposals).
If null, only the top state is popped
Now, I do realize that I'm lacking knowledge of your particular implementations (like how many entries you have in the back stack at the given point in time), but I would bet all my money on the accepted answer when expecting a well defined behaviour over a wider range of devices and vendors:
(for reference, something along with this)
FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
fm.popBackStack();
}
Clear backstack without loops
String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Where name is the addToBackStack() parameter
getSupportFragmentManager().beginTransaction().
.replace(R.id.container, fragments.get(titleCode))
.addToBackStack(name)
Works for me and easy way without using loop:
FragmentManager fragmentManager = getSupportFragmentManager();
//this will clear the back stack and displays no animation on the screen
fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Accepted answer was not enough for me. I had to use :
FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
fm.popBackStackImmediate();
}
Hi~I found a solution which is much better,from: https://gist.github.com/ikew0ng/8297033
/**
* Remove all entries from the backStack of this fragmentManager.
*
* #param fragmentManager the fragmentManager to clear.
*/
private void clearBackStack(FragmentManager fragmentManager) {
if (fragmentManager.getBackStackEntryCount() > 0) {
FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
fragmentManager.popBackStack(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
I just wanted to add :--
Popping out from backstack using following
fragmentManager.popBackStack()
is just about removing the fragments from the transaction, no way it is going to remove the fragment from the screen.
So ideally, it may not be visible to you but there may be two or three fragments stacked over each other, and on back key press the UI may look cluttered,stacked.
Just taking a simple example:-
Suppose you have a fragmentA which loads Fragmnet B using fragmentmanager.replace() and then we do addToBackStack, to save this transaction.
So the flow is :--
STEP 1 -> FragmentA->FragmentB (we moved to FragmentB, but Fragment A is in background, not visible).
Now You do some work in fragmentB and press the Save button—which after saving should go back to fragmentA.
STEP 2-> On save of FragmentB, we go back to FragmentA.
STEP 3 ->So common mistake would be... in Fragment B,we will do fragment Manager.replace() fragmentB with fragmentA.
But what actually is happenening, we are loading Fragment A again, replacing FragmentB . So now there are two FragmentA (one from STEP-1, and one from this STEP-3).
Two instances of FragmentsA are stacked over each other, which may not be visible , but it is there.
So even if we do clear the backstack by above methods, the transaction is cleared but not the actual fragments.
So ideally in such a particular case, on press of save button you simply need to go back to fragmentA by simply doing fm.popBackStack() or fm.popBackImmediate().
So correct Step3-> fm.popBackStack() go back to fragmentA, which is already in memory.
For the kotlin people around here:
repeat(supportFragmentManager.backStackEntryCount) {
supportFragmentManager.popBackStack()
}
Reading the documentation and studying what the fragment id is, it appears to simply be the stack index, so this works:
fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Zero (0) is the the bottom of the stack, so popping up to it inclusive clears the stack.
CAVEAT: Although the above works in my program, I hesitate a bit because the FragmentManager documentation never actually states that the id is the stack index. It makes sense that it would be, and all my debug logs bare out that it is, but perhaps in some special circumstance it would not? Can any one confirm this one way or the other? If it is, then the above is the best solution. If not, this is the alternative:
while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }
Just use this method and pass Context & Fragment tag upto which we need to remove the backstake fragments.
Usage
clearFragmentByTag(context, FragmentName.class.getName());
public static void clearFragmentByTag(Context context, String tag) {
try {
FragmentManager fm = ((AppCompatActivity) context).getSupportFragmentManager();
for (int i = fm.getBackStackEntryCount() - 1; i >= 0; i--) {
String backEntry = fm.getBackStackEntryAt(i).getName();
if (backEntry.equals(tag)) {
break;
} else {
fm.popBackStack();
}
}
} catch (Exception e) {
System.out.print("!====Popbackstack error : " + e);
e.printStackTrace();
}
}
It is working for me,try this one:
public void clearFragmentBackStack() {
FragmentManager fm = getSupportFragmentManager();
for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
fm.popBackStack();
}
}
I got this working this way:
public void showHome() {
getHandler().post(new Runnable() {
#Override
public void run() {
final FragmentManager fm = getSupportFragmentManager();
while (fm.getBackStackEntryCount() > 0) {
fm.popBackStackImmediate();
}
}
});
}
private void clearBackStack(){
SupportFragmentManaer fm = getSupportFragmentManager();
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
Call to this method would be very neat.
No Loop required.
If you are using animation in fragments, it will not show too many animations. But using loop will.
private boolean removeFragFromBackStack() {
try {
FragmentManager manager = getSupportFragmentManager();
List<Fragment> fragsList = manager.getFragments();
if (fragsList.size() == 0) {
return true;
}
manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}