Get that a fragment is first item in stackk - android

I have an activity that manages a list of fragments. Each Time I want to add a fragment to the stack i call
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.layout, fragment, tag);
ft.addToBackStack(null);
Then I constantly push/pop different fragments on and off the stack. When I push them off i call
getFragmentManager().popBackStackImmediate();
Does anyone know of a way for the Fragment to know that it is now the top fragment in the stack? i.e. I have a fragments on a stack in order of A B C D. If i pop D off the stack, is there anyway for C to know that it is currently on the top of the stack?
Thanks in advance!

In your ft.addToBackStack(null);, set a name instead of null. You can then use this to identify a backstack entry.
i.e.
BackStackEntry currentBackStack = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount()-1);
currentBackStack.getName();//your identifier
This gets the last item in the backstack, and gets the name of that backstack entry.
You can do this in each fragment, and check if the name matches.

Related

android: return to specific Fragment (and pop off everything after it)

Let's say in my app there are a few possible navigation flows (all are Fragments)
A -> B -> C -> D -> E
A -> F -> B -> C
I'd like to be able to return to fragment B regardless of the transaction backstack depth (ie. I don't want to keep track if I'm currently showing E or C). I noticed it's possible to tag the fragments, but the following code doesn't seem to work:
In fragment A create fragment B aka SocialViewFragment:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Method 1
transaction.add(R.id.fragment_container, frag, SocialViewFragment.FRAG_TAG).commit();
// Method 2
//transaction.replace(R.id.fragment_container, frag);
//transaction.addToBackStack(SocialViewFragment.FRAG_TAG).commit();
Then in Fragment E, popBackStack returns false (and does nothing), cause it can't find the tag?!
FragmentManager mgr = PlaybackFrag.this.getActivity().getSupportFragmentManager();
if (mgr.getBackStackEntryCount() > 0) {
// Want to go back to SocialViewFragment !!!
mgr.popBackStack(SocialViewFragment.FRAG_TAG, 0); // returns False - can't find the tag!
}
It looks as though you are confusing two different types of tags.
The optional String parameter you can pass to add() is a tag for the Fragment that allows you to later find the same Fragment by calling findFragmentByTag().
The optional String parameter passed to addToBackStack() and popBackStack() is referred to as a "name" and is used to identify a particular transaction in the FragmentManager's back stack. It is not a Fragment tag because a back stack entry represents a particular transaction that could have multiple Fragment additions or removals.
To utilize the back stack names correctly, make sure you call addToBackStack() with a non-null String, then later you can call popBackStack() with the same String to pop to that particular transaction.
Also note that in your add() call you aren't calling addToBackStack() at all. Because of this, mgr.getBackStackEntryCount() will be 0 and your popBackStack() call will never happen at all (unless you have added other Fragments to the back stack).
In order to popBackStack you should addToBackStack first.
Use the method that is commented in your code:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, frag);
transaction.addToBackStack(SocialViewFragment.FRAG_TAG).commit();

Get fragment from backstack

Hardly can't get fragment from backstack, even start thinking of keeping in in singleton which is probably bad.
Saved to backstack like this and all time try to get it by tag or something gives me error.
Fragment fragment = UserProfileFragment.newInstance(null);
FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.replace(FRAGMENT_PLACE_RESOURCES, fragment);
trans.addToBackStack("profile");
trans.commit();
It just return me null here so I can't use this fragment. No logs.
Fragment fragment2 = getFragmentManager().findFragmentByTag("profile");
getFragmentManager().findFragmentByTag("tag")
is only used when you have added a fragment with specific tag for e.g.
fragmentTransaction.add(R.id.order_container,mProfileFragment,"profile");
or
fragmentTransaction.replace(R.id.order_container,mProfileFragment,"sometag");
Then you will be able to find this fragment by the tag.
In your case you are adding a transaction to backstack so you will not be able to find that fragment by tag. You just adding a transaction to backstack thats it not a fragment. And also your fragment was removed from the activity and destroyed so you have to revert the transaction by popping backstack instead of finding that fragment by tag.
You have to call
getFragmentManager().popBackStack("profile");
to get that fragment back to the activity and make it visible on screen.

Android BackStack NavigationDrawer

I have a problem that I've been dealing with for the last couple o days and don't seem to find an answer to it.
Description : I have a main activity which contains a navigation drawer. Each item of the navigation drawer (when clicked) creates a fragment. In that fragment, there is a listView of objects, which creates other fragments when clicked. In those fragments i have another listView of objects which opens other fragments. In other words, there series of fragment that open other fragment. Something like this:
http://s22.postimg.org/pddo5gsv5/backstack.png
In order to be able to get back to each fragment, I've implemented the addToBackstack("string") method.
My question is, how can I implement correct backstack for my application so that when i click a navigation Drawer item, all the fragments that have been added to backstack are cleared, without the one that the navigation Drawer item opens.
Any help would be appreciated. Thank you !
EDIT
Ok, it seems I managed to figure it out. Considering what advices i received from the replies, here's the solution I came up with:
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count != 0) {
FragmentManager.BackStackEntry backEntry = getFragmentManager()
.getBackStackEntryAt(
getFragmentManager().getBackStackEntryCount() - 1);
if (backEntry.getName() == NAVIGATION) {
finish();
} else
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
To put it in words: First, i added a backstack entry even for the top level fragments, given them a specific tag. The I have overridden the Activity's back button function so that when the last backstack entry is a top-level fragment to finish the activity (so that it not simply detach the fragment from activity, living it empty). Otherwise, if the last entry isn't an top-level fragment, execute a popBackStack.
PS: All non-top-level fragments are added to the backstack with a different tag then the top-level one. Also, i had to do a POP_BACK_STACK_INCLUSIVE in the navigation Drawer's click listener.
getFragmentManager().popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
Thank you all for the advices and hopefully this EDIT help other users.
You can use the following code to solve your problem:
getFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(fragment_tag)
.commit();
In order to make the code above work, you have to create the fragments dynamically. As hardcoded fragments cannot be replaced. To do that, you can create a container (FrameLayout etc.) which in our example has the id fragment_container. Then, the code above will add the fragment in the container dynamically. Finally, you have to pass as parameter in the addToBackStack method the fragment_tag. That means, that this transaction will be added in the back stack. And finally, in order to get it from the backstack you have to use the code below:
getFragmentManager().popBackStack(fragment_tag, FragmentManager.POP_BACK_STACK_INCLUSIVE));
The POP_BACK_STACK_INCLUSIVE flag, insures that "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."
You can clear the fragment backstack by using something like:
fragmentManager.popBackStack("string", FragmentManager.POP_BACK_STACK_INCLUSIVE);
and then you can addToBackstack and commit as usual. More info.
A code snippet that shows the way I normally use it in navigation drawers:
FragmentManager fragmentManager = getSupportFragmentManager();
if(clearBackStack) {
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
if(!clearBackStack) {
ft.addToBackStack(null);
}
ft.commit();

How to get a reference to the last backstack popped fragment?

I add, show and hide fragments. Each time I add/show a fragment, I hide the previous fragment and add the transaction to the backstack.
When a user presses the back button, a fragment is popped and I would like to have a reference to it.
Why do I need a reference? So I could hide it when the user continues to the next fragment.
So, how do I get a reference to a popped fragment?
EDIT-25-04-2013:
Here's code to explain how to add a new fragment, while hiding the previous one. The question is how to get a reference to the last fragment after it is popped from the backstack (using the back button)?
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.hide(lastFragment);
fragmentTransaction.add(newFragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
lastFragment = newFragment;
I use generated tags for each fragment, save the tags in a stack and persist the stack. This way I get hold of every fragment out there - last one in specific.
See the code here.

Is this the right way to clean-up Fragment back stack when leaving a deeply nested stack?

I'm using the Android Compatibility library to implement fragments and have extended the layout sample so that a fragment contains a button which fires off another fragment.
In the selection pane on the left I have 5 selectable items - A B C D E.
Each loads up a fragment (via FragmentTransaction:replace) in the details pane - a b c d e
Now I've extended fragment e to contain a button which loads up another fragment e1 also in the details pane. I've done this on fragment e's onClick method as follows:
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details_frag, newFrag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
If I make the following selections:
E - e - e1 - D - E
Then fragment e is in the details pane. This is fine and what I want. However, if I hit the back button at this point it does nothing. I have to click it twice because e1 is still on the stack. Furthermore after clicking around I got a null pointer exception in onCreateView:
To 'solve' this problem I added the following whenever A B C D E is selected:
FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
fm.popBackStack();
}
Just wondering whether this is the correct solution or whether I should be doing something different?
Well there are a few ways to go about this depending on the intended behavior, but this link should give you all the best solutions and not surprisingly is from Dianne Hackborn
http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42
Essentially you have the following options
Use a name for your initial back stack state and use
FragmentManager.popBackStack(String name,
FragmentManager.POP_BACK_STACK_INCLUSIVE).
Use FragmentManager.getBackStackEntryCount()/getBackStackEntryAt().getId()
to retrieve the ID of the first entry on the back stack, and
FragmentManager.popBackStack(int id,
FragmentManager.POP_BACK_STACK_INCLUSIVE).
FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
is supposed to pop the entire back stack... I think the documentation for
that is just wrong. (Actually I guess it just doesn't cover the case where
you pass in POP_BACK_STACK_INCLUSIVE),
The other clean solution if you don't want to pop all stack entries...
getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_container, fragmentInstance).addToBackStack(null).commit();
This will clean the stack first and then load a new fragment, so at any given point you'll have only single fragment in stack
Thanks to Joachim answer, I use the code to clear all back stack entry finally.
// In your FragmentActivity use getSupprotFragmentManager() to get the FragmentManager.
// Clear all back stack.
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < backStackCount; i++) {
// Get the back stack fragment id.
int backStackId = getSupportFragmentManager().getBackStackEntryAt(i).getId();
getSupportFragmentManager().popBackStack(backStackId,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
} /* end of for */
I have researched a lot for cleaning Backstack, and finally see Transaction BackStack and its management. Here is the solution that worked best for me.
// CLEAR BACK STACK.
private void clearBackStack() {
final FragmentManager fragmentManager = getSupportFragmentManager();
while (fragmentManager.getBackStackEntryCount() != 0) {
fragmentManager.popBackStackImmediate();
}
}
The above method loops over all the transactions in the backstack and removes them immediately one at a time.
Note: above code sometime not work and i face ANR because of this code,so please do not try this.
Update
below method remove all fregment of that "name" from backstack.
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
name 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.
I'm using a similar code as those that use the while loop but I call the entry count in every loop... so I suppose it's somewhat slower
FragmentManager manager = getFragmentManager();
while (manager.getBackStackEntryCount() > 0){
manager.popBackStackImmediate();
}
As written in How to pop fragment off backstack and by LarsH here, we can pop several fragments from top down to specifical tag (together with the tagged fragment) using this method:
fragmentManager?.popBackStack ("frag", FragmentManager.POP_BACK_STACK_INCLUSIVE);
Substitute "frag" with your fragment's tag. Remember that first we should add the fragment to backstack with:
fragmentTransaction.addToBackStack("frag")
If we add fragments with addToBackStack(null), we won't pop fragments that way.
// pop back stack all the way
final FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
int entryCount = fm.getBackStackEntryCount();
while (entryCount-- > 0) {
fm.popBackStack();
}

Categories

Resources