Suppose we have three fragments hosted in an activity on our back stack
A->B->C
When I click on back press on fragment C I also want to immediately remove B from the back stack.Note that in some cases I might want to go back to B but for the most part I want to clear out C and B together to get to A.How can I achieve this should I call popBackStack() twice or should I have some kind of delegate mechanism to notify B that C has been closed and we don't expect to show B so please clean up.
In fragment A do this..
getSupportFragmentManager().beginTransaction()
.add(R.id.containerMain, new FragmentA()).addToBackStack("BACKSTACK_FRAGMENT_A")
.commit();
and do not use addToBackStack(..)
in this case you'll always return to Fragment A when you press back from other Fragments.
and when are going to specify back press to specific fragment
Add Fragments To BackStack. Before commit() the transaction, use addToBackStack() method i.e
addToBackStack("Some String").commit();
and in onBackPressed()
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
} else {
this.finish();
}
}
Related
I have only one activity in my application with multiple fragments. Whenever a user opens the app, it starts with startupFragment. Whenever user navigate through the fragments and presses back, it takes him back to startupFragment. But when in the startupFragment, I want user, when clicked back, to be able to close the application. Now, here is the code, when the application is started for creating the fragment.:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Set starting fragment
StartupFragment startupFragment = new StartupFragment();
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().add(R.id.content_main, startupFragment, "startupFragmentTag").commit();
}
As you can see, I have added the tag "startupFragmentTag" to be able to identify it. This is my code onBackPressed:
#Override
public void onBackPressed()
{
Fragment startup = getFragmentManager().findFragmentByTag("startupFragmentTag");
if(startup == null) {
android.support.v4.app.FragmentManager manager = getSupportFragmentManager();
StartupFragment startupFragment = new StartupFragment();
manager.beginTransaction().replace(R.id.content_main, startupFragment, "startupFragmentTag").commit();
} else {
finish();
}
}
So basically what I tried here, is when user is in another fragment, when the user presses back, it will take him/her back to startupFragment. But when in that fragment, when pressing back again, I want the user to be able to exit the application, which won't happen given the code now.
I find the startupFragment by its tag and check if it exists. If not, it will take back the user to it. But if it exists, user should be able to quit, that why finish() is called.
Does the previous fragments not get destroyed? But that shouldn't be the case, because even if I open the app and instantly press back, it won't exit the app.
What am I doing here wrong?
It looks like all you need to do is add each Fragment to the back stack on each FragmentTransaction, and then pop each Fragment from the back stack in onBackPressed().
First, modify onCreate() so that on each transaction, it calls addToBackStack():
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Set starting fragment
StartupFragment startupFragment = new StartupFragment();
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.content_main, startupFragment, "startupFragmentTag")
.addToBackStack(null)
.commit();
}
Then, in onBackPressed(), just pop from the back stack if you're not on the starting Fragment. If you're on the starting Fragment, and back is pressed, just call super.onBackPressed(), which will exit the app:
#Override
public void onBackPressed() {
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 1) {
//Go back to previous Fragment
fragmentManager.popBackStackImmediate();
} else {
//Nothing in the back stack, so exit
super.onBackPressed();
}
}
You're working with fragments, so to finish your app you need to finish the parent activity.
Try this to finish the activity from startupfragment:
getActivity().finish();
Probably because you've used beginTransaction().add() to add the Fragments including startupFragment and other Fragments on top of it. Then you will always be able to find it using getFragmentManager().findFragmentByTag(), because all Fragments added will be in the Fragment stack (while the find method is actually to find the Fragment with the tag in the stack).
Tips based on what you want to impl:
beginTransaction().replace() will replace instead of adding a Fragment, this way you will only be able to "find" one existing Fragment if you always replace it. i.e. always one Fragment in the stack.
You may want to use getFragmentManager().findFragmentById() to get current showing Fragment (on top of the Fragment stack), instead of findFragmentByTag, if there're several Fragments in the stack which are added not replaced as mentioned above.
When using beginTransaction().add(), you may want to use fragmentManager.addOnBackStackChangedListener() to monitor the Fragment stack changes. Then you probably don't have to handle onBackPressed(). Then in the in the listener you only need to retrieve current Fragment on top stack and see what it is and add your logic there.
I have fragment A and adding fragment B in same container (not replacing). I am adding this transaction on backstack also. Now, when device back is pressed, fragment B will be removed and fragment A will become visible. I want to do something when fragment A becomes visible. I searched lot but could not find anything helpful.
Note - I don't want to add backstackchangelistner and call onResume on that fragment.
You can override onHiddenChanged(boolean hidden) in a Fragment.
This will be called when its shown/hidden.
I use the same approach in my app, where i add a fragment and hide the old one, and then use the onHiddenChanged callback when the user presses Back, and the old fragment is shown again.
As you have 2 entries in Back stack, you can check back stack count on
Back Pressed method.
FragmentManager mFragmentManager = getSupportFragmentManager();
int count= mFragmentManager.getBackStackEntryCount();
if(count==1){
// do your work
}
you can try
#Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
}
or
`fragment.isVisible();`
I'm so very confused and have been reading on this topic for a while.
I have a MainActivity that has multiple possible contents (switched between via navigation drawer), which I've set via multiple fragments (lets call them Fragment1, Fragment2 and Fragment3).
That works fine.
One of my fragments, Fragment3, is a View that can segue to a new activity, View2.
View2 has a back button. When I press on the View2 back button I want to see Fragment3 on my MainActivity, not Fragment1, which is what I currently get. This is because OnCreate, by default, loads Fragment1.
What is the best way to do this?
Thanks so much in advance! (vent: iOS makes this so much easier).
The official documentation for Fragments states that you should make sure to call addToBackStack() before commiting your fragment transaction on your first activity holding the 3 fragments.
In order to go back to the last used fragment from the second activity , you should override the onBackPressed() method in this activity :
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
The documentation is very complete on the subject : Read it here
Update:
I just added this to the back button code:
finish();
return true;
I had to do it within onOptionsItemSelected(MenuItem item)... for some reason onBackPressed is not fired.
My app use 5 fragment, like this:
[1]through[onClick on actionBar defined in activity]->[2]->[3]->[4]->[5]
Each fragment is added to the back stack so I can go back while pressing the back button. However, I would like to return to the first fragment when pressing the back button on the 5th fragment, like this:
[1]<-[2]<-[3]<-[4] [1]<-[5]
I tried to make it this way:
fragmentTransaction.addToBackStack("firstfragmenttag");
When adding the 5th fragment on the 4th one, but when I press the back button it still send me back to the 4th instead of the 1st! Is it a simple way do do that programmatically? Thanks in advance.
In your case, you just need to add first fragment in stack.
No need to add others to stack
This could be achieved in following way:
Fragment F1 = new <Fragment Name>();
fragmenttransaction.add(R.id.content,F1).commit();
And for others like F2,F3,F4 & F5
you could use
Fragment F2 = new <Fragment Name>();
fragmenttransaction.replace(R.id.content,F2).addToBackstack(null).commit();
And then you need to override OnBackpressed [inside Activity] like below:
#Override
public void onBackPressed() {
if(getSupportFragmentManager().getBackStackEntryCount() >0) {
getSupportFragmentManager().popBackStack();
}
else{
super.onBackPressed();
}
}
Hope it helps!
you can actually get the backstack count in onBackPressed and check count , if it is 5 then perform popfrombackstack 4 times to get back to 1 fragment
Im trying to Solve a problem where when a user press back key, the fragment should be recreated rather than loading from back stack. I have a single Main activity with a frame layout and i replace the fragments within the single frame dynamically. the code below works when the user go from fragment within fragment. but when the user select from navigation drawer, the replaced fragment is going on to the top of backstack which is causing problems.
Right now the code i wrote in BackKey Pressed Event
public override void OnBackPressed()
{
Android.Support.V4.App.FragmentManager.IBackStackEntry entry =
SupportFragmentManager.GetBackStackEntryAt(SupportFragmentManager.BackStackEntryCount - 1);
string str = entry.Name;
if (SupportFragmentManager.BackStackEntryCount == 0)
{
this.Finish();
}
else
{
Fragment fr = (Fragment)MagicallyCreateInstance(str);
SupportFragmentManager.BeginTransaction().Replace(Resource.Id.content_frame, fr).Commit();
SupportFragmentManager.PopBackStack();
}
base.OnBackPressed();
}
i also have a replace fragment method which i use to replace fragments. but in this process the back key is getting disabled by default somehow (Not sure how) but whenever there is existing fragment in the backstack, the old UI is getting loaded. Can i refresh the layout here?
public void ReplaceFragment(Fragment fragment, FragmentManager fragmentManager)
{
string backStateName = fragment.Class.SimpleName;
bool fragmentPopped = fragmentManager.PopBackStackImmediate(backStateName, 0);
if (!fragmentPopped && fragmentManager.FindFragmentByTag(backStateName) == null)
{
fragmentManager.BeginTransaction()
.Replace(Resource.Id.content_frame, fragment).SetTransitionStyle(FragmentTransaction.TransitFragmentFade)
.AddToBackStack(backStateName)
.Commit();
}
}
Can anyone please help me solve this any one of the above?
I hope I'm understanding your problem correctly. But it sounds like you want to make sure that when the user selects a destination from your main navigation you want to make sure the back stack is cleared or reset.
Ex:
Stack looks like this:
A->B->C
User selects D from main navigation, stack should look like:
D
NOT
A->B->C->D
If this is the case, you should clear the back stack before navigating to any top-level destinations. This can be done like so:
FragmentManager.PopBackStack(null, FragmentManager.PopBackStackInclusive);
The documentation for this method is not great, but it will pop everything off the back stack. A discussion can be found here: https://groups.google.com/d/msg/android-developers/0qXCA9rW7EI/M9riRM0kl9QJ