Currently, I have a Fragment stack like this.
F1 -> F2 -> F3 -> F4 -> F5
And in an activity, I have one button B1.
My question is when I press B1 button from the activity how can I update Fragment stack like below.
F2 -> F3 -> F4 -> F5 -> F1.
I have used string tags at the time of addtobackstack.
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.
I solved this by this code:
public void fragmentInflater(Fragment newFragment) {
FragmentTransaction transaction;
FragmentManager fragmentManager = getSupportFragmentManager();
transaction = fragmentManager.beginTransaction();
Fragment oldFragment = fragmentManager.findFragmentByTag(newFragment.getClass().getName());
if (oldFragment == null) {
transaction.replace(R.id.container, newFragment, newFragment.getClass().getName());
transaction.addToBackStack(null);
} else {
transaction.replace(R.id.container, oldFragment, newFragment.getClass().getName());
}
transaction.commit();
}
Use this method for adding fragments to your container and you will achieve what you want. It will also prevents adding duplicated fragments to your container.
Related
I need to be able to go through fragments like this: A->B->C1
When I'm on C1 I need to replace it with C2, but when I press back I should be taken back to B instead of C1.
I'm able to do this like this:
String tag = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
manager.popBackStack();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.mainActivity_container, fragment, tag);
ft.addToBackStack(tag);
ft.commit();
The problem is that while I'm changing from C1 to C2, fragment B gets it's onCreateInnerView method called.
I need to be able to do something like this: A->B->C1->C2->C1->C2 and by pressing back in C2 I should go to B
How to execute replacement without recreating fragment B?
You can handle the onBackPressed() event and replace whatever is the current fragment to fragment B.
First thing You don't need to popupstack while moving to fragment. Because It will call your last stack's fragment onViewCreated method.
While moving to B -> C1 , B -> C2 and C1 -> C2 :
Need to add Back stack null
Remove popupbackstack
I hope it will works for you.
Try this might be help you,
Just replace two line ,
manager.popBackStack();//Remove this line
ft.replace(R.id.mainActivity_container, fragment);//Remove 3rd param in this line
ft.addToBackStack(tag);//Remove this line
EDITED
you can also try this
public void switchContent(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
for (int i = 0; i < fragmentManager.getBackStackEntryCount(); ++i) {
Fragment currentFragment = this.getSupportFragmentManager().findFragmentById(R.id.mainActivity_container);
if(currentFragment != B){
fragmentManager.popBackStack();
}
}
fragmentTransaction.replace(R.id.mainActivity_container, fragment).commit();
}
I have the following fragments in the back stack A, B, C. Then I want to add fragment D, but in the back stack I want to put A and D instead of A, B, C, D.
The problem is when I try to remove B and C with transaction.remove(), the backStackEntryCount is still the old one, which makes empty screens while pressing back. Is there a way to handle this?
When I use popBackStack()it goes to fragment A then comes D, which makes weird animation effects.
EDIT:
The question is not duplicate as it was marked, because this question is more about to control the order of several fragments in the back stack.
When adding to the Backstack, you can include a name to pop the backstack to when you're in a specific state. Based on the documentation for FragmentManager#popBackStack(string, int);:
Pop the last fragment transition from the manager's fragment back stack. If there is nothing to pop, false is returned. This function is asynchronous -- it enqueues the request to pop, but the action will not be performed until the application returns to its event loop.
Parameters
name String: If non-null, this is the name of a previous back state to look for; if found, all states up to that state will be popped. The POP_BACK_STACK_INCLUSIVE flag can be used to control whether the named state itself is popped. If null, only the top state is popped.
flags int: Either 0 or POP_BACK_STACK_INCLUSIVE.
So in this case you:
Add fragment A to the container and to the root backstack. Give it a name so you can reference it when popping.
Fragment A:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, FragmentA, "FragmentA")
.addToBackStack("first")
.commit();
Add Fragment B to the container (replace or add, doesn't matter). Add to the backstack with a "null" or another name if you prefer. It must be different than "first".
Fragment B:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, FragmentB, "FragmentB")
.addToBackStack(null)
.commit();
Add or replace with Fragment C like you would with Fragment B.
Fragment C:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, FragmentC, "FragmentC")
.addToBackStack(null)
.commit();
Add or replace with Fragment D like you would with Fragment B and C.
Fragment D:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, FragmentD, "FragmentD")
.addToBackStack(null)
.commit();
Then, in onBackPressed() you first check if "FragmentD" is in the stack. If it is, then pop all the way back to the root (which in this case is "first"). If not, just handle the back pressed like you normally would.
#Override
public void onBackPressed() {
FragmentManager fm = getFragmentManager();
if (fm.findFragmentByTag("FragmentD") != null) {
fm.popBackStack("first", 0); // Pops everything up to "first"
} else {
super.onBackPressed(); // Pops backstack like normal or leaves App if at base.
}
}
What this should do is allow your users to go "back" when they press the back button in Fragments A, B, or C. Then when they're finally in Fragment D, it will pop all the way back to A.
Fragment A
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, FragmentA, "FragmentA");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Fragment B
fragmentTransaction.replace(R.id.fragment_container, FragmentB, "FragmentB");
Fragment C
fragmentTransaction.replace(R.id.fragment_container, FragmentC, "FragmentC");
Fragment D
fragmentTransaction.replace(R.id.fragment_container, FragmentD, "FragmentD");
Now your onBackPressed() in activity
#Override
public void onBackPressed() {
int lastStack = getSupportFragmentManager().getBackStackEntryCount();
try {
//If the last fragment was named/tagged "three"
if (getSupportFragmentManager().getFragments().get(lastStack).getTag().toString()=="FragmentD"){
getSupportFragmentManager().popBackStackImmediate();//skip c
getSupportFragmentManager().popBackStackImmediate();//skip B
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentA");
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.commit();
return;
}
} catch (Exception e) {
e.printStackTrace();
}
super.onBackPressed();
}
make fragment_container for each of the fragment and keep on replacing the newest fragment's fragment_container..
Dont forget:
addToBackStack(null);
I have a problem about removing a specific fragment from back stack.My scenario is like this.Fragment-1 is replaced with Fragment-2 and then Fragment-2 is replaced with Fragment-3.
Calling order; Fragment-1-->Fragment-2-->Fragment-3.
When Fragment-3 is on the screen and then back button is clicked, i want to go
Fragment-1.That means i want to delete Fragment-2 from back stack.
How to do this ?
In the backstack you don't have Fragments, but FragmentTransactions. When you popBackStack() the transaction is applied again, but backward. This means that (assuming you addToBackStackTrace(null) every time) in your backstack you have
1->2
2->3
If you don't add the second transaction to the backstack the result is that your backstack is just
1->2
and so pressing the back button will cause the execution of 2->1, which leads to an error due to the fragment 2 not being there (you are on fragment 3).
The easiest solution is to pop the backstack before going from 2 to 3
//from fragment-2:
getFragmentManager().popBackStack();
getFragmentManager().beginTransaction()
.replace(R.id.container, fragment3)
.addToBackStack(null)
.commit();
What I'm doing here is these: from fragment 2 I go back to fragment 1 and then straight to fragment 3. This way the back button will bring me again from 3 to 1.
I had a very similar scenario to yours, my solution was just checking the amount of backStack transactions that I had.
If the transactions where more than 0 then I would simply pop it right away
so it would skip it when pressing back.
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStackImmediate();
}
...
fragmentTransaction.replace(R.id.main_fragment, newFrag, MAIN_FRAGMENT_TAG);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.commit();
This would successfully:
A -> B (back pressed) -> back to A
A -> B -> C (back pressed) -> back to A
The only downside that I see is that there is a quick flash where fragment A is displayed before going to fragment C.
If you are adding/launching all three fragments in the same activity, instead of the add(), use replace() (replace Fragment2 with Fragment3). The replace method removes the current fragment from backstack before adding the new one. If you are launching Fragment3 from a different activity, and thus you can't use replace(), remove Fragment2 from backstack before starting the new activity (which adds Fragment3):
// in Fragment2, before adding Fragment3:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.remove(this) // "this" refers to current instance of Fragment2
.commit();
fragmentManager.popBackStack();
// now go ahead and launch (add) fragment3
// if fragment3 is launched from a different activity,
// start that activity instead
fragmentManager.beginTransaction()
.add(R.id.a_container_view_in_activity, new Fragment3(),
Fargment3.FRAGMENT3_ID)
.commit();
Code for Fragment A -> Fragment B:
Add Fragment A in BackStack of Fragments
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout_container, new fragmentB());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Code for Fragment B -> Fragment C:
Do not Add Fragment B in BackStack of Fragments
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout_container, new fragmentC());
fragmentTransaction.commit();
It will works in this way: A -> B -> C and while returning C-> A as you excepted.
Hope it will help you.
for (int i = 0; i < mFragmentManager.getBackStackEntryCount(); i++) {
currentFragment = mFragmentManager.getFragments().get(i);
if (!(currentFragment instanceof ParticularFragment))
mFragmentManager.popBackStack();
else
break;
}
My activity consists of navigation drawer and currently have 5 options in the left menu. Which all opens in fragment.
I am looking for a way to keep a stack of all the fragments so when the user presses back button he moves to previous fragment.
Like- Activity consists of drawer menu which have 5 options menu1, menu2, menu3, menu4, menu5 having corresponding fragments F1, F2, F3, F4, F5.
User presses menu1 he is forwarded to F1
Then presses menu2, and then menu4.
When the user is at F4 and he presses back he should be moved to F2 rather than exiting the activity or app.
How can it implemented and example or sample code preferred.
I currently use this code but it does not help me out
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment)
.addToBackStack(null)
.commit();
I found some workaround for your query :
Override onBackPressed() in code
Use methods related to backstack maintained which contains your all fragment transactions
public void onBackPressed(){
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0) {
Log.i("MainActivity", "popping backstack");
fm.popBackStack(); // this will display last visible fragment
getActinBar().setTitle(mTitle); // save your title in some variable and restore here
} else {
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed(); // system will handle back key itself
}
}
Reference answer : this
I used to replace Fragment like as below :
public void replaceFragment(Fragment fragment, boolean addToBackStack, int transition) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.activity_main_relative_container, fragment, fragment.getClass().getName());
ft.setTransition(transition);
if (addToBackStack) {
ft.addToBackStack(fragment.getClass().getName());
}
ft.commitAllowingStateLoss();
}
// While to replace Fragment
replaceFragment(mFragment, true, FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
// False for not adding Fragment in back stack and true to add.
Hope this helps.
You need to add fragment to backstack
private FragmentTransaction m_fragmentTransaction;
FragmentOne m_fragOne = new FragmentOne();
m_fragmentTransaction = m_fragmentManager.beginTransaction();
m_fragmentTransaction.replace(R.id.dl_flContainer, m_fragOne , FragmentOne.class.getSimpleName());
m_fragmentTransaction.addToBackStack(FragmentOne.class.getSimpleName());
m_fragmentTransaction.commit();
Currently, I am working on a new android project.
In my project, I have 2 FrameLayout (called F1, F2) which are used as containers of Fragment.
On "F1" I will add a fragment (Like navigation drawer fragment, menu item....).
On "F2" I called its MainContainer - It's will use container all "Main" fragment. (I mean F2 will container fragment like HomeFragment, GameFragment......).
Here are some steps:
F1 -> add fragment f1;
F1 -> add fragment f2;
F2 -> add fragment g1;
F2 -> add fragment g2;
F1 -> add fragment f3;
Now I want to use the transaction fragment on Container F2.
I mean:
I can add/remove a fragment on Container F2. But in android Fragment Manager will manager all Fragment f1..f3, g1..g2;
So I called popBackStack -> It's will remove fragment f3. (But I want to remove g2).
For any task like addFragment, remove, replace fragment I only want to do Fragment in Container F2. (F1 will be never changed).
Please help!
When you adding the fragment, you can use addToBackStack(String name) and disallowAddToBackStack() to control the back stack of FragmentManager.
For your requirement, you should use the code like this to add f1, f2, and f3:
getFragmentManager().beginTransaction()
.add(R.id.F1, [your fragment instance])
.disallowAddToBackStack()
.commit();
And use the code like below to add g1 and g2:
getFragmentManager().beginTransaction()
.add(R.id.F2, [your fragment instance])
.addToBackStack(null)
.commit();
Check the officail document of addToBackStack(String name) and disallowAddToBackStack() for more details.
You should use child fragment when adding child to that fragment.
public void addFragB() {
FragmentManager childFragMan = getChildFragmentManager();
FragmentTransaction childFragTrans = childFragMan.beginTransaction();
FragmentClassB fragB = new FragmentClassB();
childFragTrans.add(R.id.fragA_LinearLayout, fragB);
childFragTrans.addToBackStack("B");
childFragTrans.commit();
}
And when removing the fragment
public void backPressed() {
int childCount = parentFragment.getChildFragmentManager().getBackStackEntryCount();
if (childCount == 0) {
// it has no child Fragment
} else {
// get the child Fragment
FragmentManager childFragmentManager = parentFragment.getChildFragmentManager();
// removing the child Fragment from stack
childFragmentManager.popBackStackImmediate();
}
}