How to resume existing Fragment from BackStack - android

I am learning how to use fragments. I have three instances of Fragment that are initialized at the top of the class. I am adding the fragment to an activity like this:
Declaring and initializing:
Fragment A = new AFragment();
Fragment B = new BFragment();
Fragment C = new CFragment();
Replacing/Adding:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, A);
ft.addToBackStack(null);
ft.commit();
These snippets are working properly. Every fragment is attached to the activity, and is saved to the back stack without any problem.
So when I launch A, C, and then B, the stack looks like this:
| |
|B|
|C|
|A|
___
And when I press the 'back' button, B is destroyed and C is resumed.
But, when I launch fragment A a second time, instead of resuming from back stack, it is added at the top of the back stack
| |
|A|
|C|
|A|
___
But I want to resume A and destroy all fragments on top of it (if any). Actually, I just like the default back stack behavior.
How do I accomplish this?
Expected: (A should be resumed and top fragments should be destroyed)
| |
| |
| |
|A|
___
Edit: (suggested by A--C)
This is my trying code:
private void selectItem(int position) {
Fragment problemSearch = null, problemStatistics = null;
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
String backStateName = null;
Fragment fragmentName = null;
boolean fragmentPopped = false;
switch (position) {
case 0:
fragmentName = profile;
break;
case 1:
fragmentName = submissionStatistics;
break;
case 2:
fragmentName = solvedProblemLevel;
break;
case 3:
fragmentName = latestSubmissions;
break;
case 4:
fragmentName = CPExercise;
break;
case 5:
Bundle bundle = new Bundle();
bundle.putInt("problem_no", problemNo);
problemSearch = new ProblemWebView();
problemSearch.setArguments(bundle);
fragmentName = problemSearch;
break;
case 6:
fragmentName = rankList;
break;
case 7:
fragmentName = liveSubmissions;
break;
case 8:
Bundle bundles = new Bundle();
bundles.putInt("problem_no", problemNo);
problemStatistics = new ProblemStatistics();
problemStatistics.setArguments(bundles);
fragmentName = problemStatistics;
default:
break;
}
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();
// I am using drawer layout
mDrawerList.setItemChecked(position, true);
setTitle(title[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
The problem is, when I launch A and then B, then press 'back', B is removed and A is resumed. and pressing 'back' a second time should exit the app. But it is showing a blank window and I have to press back a third time to close it.
Also, when I launch A, then B, then C, then B again...
Expected:
| |
| |
|B|
|A|
___
Actual:
| |
|B|
|B|
|A|
___
Should I override onBackPressed() with any customization or am I missing something?

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.

I think this method my solve your problem:
public static void attachFragment ( int fragmentHolderLayoutId, Fragment fragment, Context context, String tag ) {
FragmentManager manager = ( (AppCompatActivity) context ).getSupportFragmentManager ();
FragmentTransaction ft = manager.beginTransaction ();
if (manager.findFragmentByTag ( tag ) == null) { // No fragment in backStack with same tag..
ft.add ( fragmentHolderLayoutId, fragment, tag );
ft.addToBackStack ( tag );
ft.commit ();
}
else {
ft.show ( manager.findFragmentByTag ( tag ) ).commit ();
}
}
which was originally posted in
This Question

Step 1: Implement an interface with your activity class
public class AuthenticatedMainActivity extends Activity implements FragmentManager.OnBackStackChangedListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
.............
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().add(R.id.frame_container,fragment, "First").addToBackStack(null).commit();
}
private void switchFragment(Fragment fragment){
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).addToBackStack("Tag").commit();
}
#Override
public void onBackStackChanged() {
FragmentManager fragmentManager = getFragmentManager();
System.out.println("#Class: SummaryUser : onBackStackChanged "
+ fragmentManager.getBackStackEntryCount());
int count = fragmentManager.getBackStackEntryCount();
// when a fragment come from another the status will be zero
if(count == 0){
System.out.println("again loading user data");
// reload the page if user saved the profile data
if(!objPublicDelegate.checkNetworkStatus()){
objPublicDelegate.showAlertDialog("Warning"
, "Please check your internet connection");
}else {
objLoadingDialog.show("Refreshing data...");
mNetworkMaster.runUserSummaryAsync();
}
// IMPORTANT: remove the current fragment from stack to avoid new instance
fragmentManager.removeOnBackStackChangedListener(this);
}// end if
}
}
Step 2: When you call the another fragment add this method:
String backStateName = this.getClass().getName();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.addOnBackStackChangedListener(this);
Fragment fragmentGraph = new GraphFragment();
Bundle bundle = new Bundle();
bundle.putString("graphTag", view.getTag().toString());
fragmentGraph.setArguments(bundle);
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragmentGraph)
.addToBackStack(backStateName)
.commit();

I know this is quite late to answer this question but I resolved this problem by myself and thought worth sharing it with everyone.`
public void replaceFragment(BaseFragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
final FragmentManager fManager = getSupportFragmentManager();
BaseFragment fragm = (BaseFragment) fManager.findFragmentByTag(fragment.getFragmentTag());
transaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
if (fragm == null) { //here fragment is not available in the stack
transaction.replace(R.id.container, fragment, fragment.getFragmentTag());
transaction.addToBackStack(fragment.getFragmentTag());
} else {
//fragment was found in the stack , now we can reuse the fragment
// please do not add in back stack else it will add transaction in back stack
transaction.replace(R.id.container, fragm, fragm.getFragmentTag());
}
transaction.commit();
}
And in the onBackPressed()
#Override
public void onBackPressed() {
if(getSupportFragmentManager().getBackStackEntryCount()>1){
super.onBackPressed();
}else{
finish();
}
}

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getFragmentManager().getBackStackEntryCount()==0) {
onResume();
}
}
});

Easier solution will be changing this line
ft.replace(R.id.content_frame, A);
to ft.add(R.id.content_frame, A);
And inside your XML layout please use
android:background="#color/white"
android:clickable="true"
android:focusable="true"
Clickable means that it can be clicked by a pointer device or be tapped by a touch device.
Focusable means that it can gain the focus from an input device like a keyboard. Input devices like keyboards cannot decide which view to send its input events to based on the inputs itself, so they send them to the view that has focus.

Related

Difference between add vs addToBackStack

Hi I have read this Difference between add(), replace(), and addToBackStack(). I have a confusion that If I add multiple fragments like below then If I press back button from fragment2 then will fragment1 will open ? If so then what is the use of addToBackStack as add already maintaining a stack.
FragmentTransaction ft = fragmentManager.beginTransaction();
Fragment fragment1 = new Fragment();
ft.add(R.id.llContainer, fragment1, "fragment_one");
Fragment fragment2 = new Fragment();
ft.add(R.id.llContainer, fragment2, "fragment_two");
ft.commit();
Well if you call multiple times add method on FragmentTransaction like this
FragmentTransaction ft = fragmentManager.beginTransaction();
Fragment fragment1 = new Fragment();
ft.add(R.id.llContainer, fragment1, "fragment_one");
Fragment fragment2 = new Fragment();
ft.add(R.id.llContainer, fragment2, "fragment_two");
ft.commit();
then both the fragments that been added to FragmentTransaction will be shown as overlapping.
Now clicking back will close the application. It won't start the previous fragment.
Hope this is what you were looking for.
Add method will not add your Fragment in BackStack. You need to verify once again.
While looking into code of addToBackStack
#Override
public FragmentTransaction addToBackStack(String name) {
if (!mAllowAddToBackStack) {
throw new IllegalStateException(
"This FragmentTransaction is not allowed to be added to the back stack.");
}
mAddToBackStack = true;
mName = name;
return this;
}
Flag mAddToBackStack = true; enabled which value is false by default. And this is the flag which is being used to add fragment into backstack. Have a look into below methods calls
#Override
public int commit() {
return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
......
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
.....
}
So what you observed is not correct. Something you are missing

Android fragment handling back button

I am creating an application with multiple fragments. I have four fragments fragment1, fragment2, fragment3, fragment4. I am moving from different orders like f1 -> f2 -> f4 -> f3 -> f1 or any other order. But when I click the back button from each fragment I need to go to the previous fragment. How to handle this.
Edit 1:
I already tried
FragmentManager fm = ((Activity) context).getFragmentManager();
for (int i = 0; i < fm.getBackStackEntryCount(); i++) {
fm.popBackStack();
}
Which is not help me to solve my issue.
Sample code of Manage Fragment back stack
private Stack<Fragment> stack = new Stack<Fragment>();
public void pushFragments(Fragment fragment, boolean shouldAnimate,
boolean shouldAdd) {
drawerClose = false;
if (shouldAdd)
stack.push(fragment);
this.changeFragment = fragment;
invalidateOptionsMenu();
changeFragment(fragment, shouldAnimate, false);
}
public void popFragments() {
/*
* Select the second last fragment in current tab's stack.. which will
* be shown after the fragment transaction given below
*/
Fragment fragment = stack.elementAt(stack.size() - 2);
// / pop current fragment from stack.. /
stack.pop();
/*
* We have the target fragment in hand.. Just show it.. Show a standard
* navigation animation
*/
this.changeFragment = fragment;
invalidateOptionsMenu();
changeFragment(fragment, false, true);
}
private void changeFragment(Fragment fragment, boolean shouldAnimate, boolean popAnimate) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
if (shouldAnimate)
ft.setCustomAnimations(R.anim.slide_in_right,
R.anim.slide_out_left);
if (popAnimate)
ft.setCustomAnimations(R.anim.slide_in_left,
R.anim.slide_out_right);
ft.replace(R.id.content_frame, fragment);
ft.commit();
}
//On BackPress just check this thing
private void backManage() {
if (stack.size() > 1) {
popFragments();
}
}
Use addToBackStack(String tag), while committing the fragment to add the fragment into the stack of your application:
getFragmentManager().beginTransaction().replace(fragmentContainer.getID(), fragment)
.addToBackStack(null).commit();`
on Activity
#Override
public void onBackPressed() {
if(check_if_backstack_is_null)
super.onBackPressed();
else
{
popupFromBackstack();
}
}
You should override onBackPressed method:
#Override
public void onBackPressed() {
if (fragment != null && fragment.getChildFragmentManager().getBackStackEntryCount() > 0){
fragment.getChildFragmentManager().popBackStack();
}else {
super.onBackPressed();
}
}
For this you can set addToBackStack to fragment transation and then call commit.
By calling addToBackStack(), the replace transaction is saved to the back stack so the user can reverse the transaction and bring back the previous fragment by pressing the Back button.
If you add multiple changes to the transaction (such as another add() or remove()) and call addToBackStack(), then all changes applied before you call commit() are added to the back stack as a single transaction and the Back button will reverse them all together.
You just need to add addToBackStack(null) by FragmentTransaction.
when you are calling next Fragment just add this method with null parameter.
Like this.
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(..............);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Use this lines of code for it:-
#Override
public void onBackPressed() {
if ( getSupportFragmentManager().getBackStackEntryCount() > 0){
fm.popBackStack();
}else {
super.onBackPressed();
}
}
To get the backStack functionality in your fragmentthan you should have use the .addToBackStack(null) , while performing the fragment transaction like below:-
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.YOUR_CONTAINER, YOUR_FRAGMENT,"TAG")
.addToBackStack(null) /// IT IS NECESSARY TO GET THE BACK STACK PROPERTY IN YOUR FRAGMENT
.commitAllowingStateLoss();

Back Navigation in Android

I am beginner in android and trying to develop an android app in which I stuck in back navigation. My issue is :
How to manage backstack with activities and fragments.
A1 activity with frag1 calls A2 activity and A2 activity displays a user list where on click of a list to check user profile, call to A1 Activity with Frag 2.
On opening of Frag2 of A1 activity, We are using intent flag: flag_activity_reorder_to_front and adding frag1 to backstack with FragmentManager transaction
Now IF I click on back then It shows A1 Activity with frag1 instead of A2 Activity.
IF I don't add frag1 into backstack then on back, It works with first back but on second back it exits from the app.
Any suggestions?
Try using single activity and handle all fragment transactions in it using an interface. Activity should implement this interface.
Example:
public interface FragChanger {
int NEXT_FRAGHELLO =1;
int NEXT_FRAGSET = 2;
int NEXT_FRAGSELECT =3;
int NEXT_FRAGLOG=4;
int NEXT_FRAGCHAT=5;
void onFragmentChange(int nextFrag);
}
The following should be in Your activity:
#Override
public void onFragmentChange(int nextFrag) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
switch (nextFrag){
case NEXT_FRAGHELLO:
break;
case NEXT_FRAGSET:
FragSet fragSet = new FragSet();
ft.replace(containerId,fragSet,"fragset");
ft.addToBackStack(null);
ft.commit();
break;
case NEXT_FRAGSELECT:
FragSelect fragSelect = new FragSelect();
ft.replace(containerId,fragSelect,"fragselect");
ft.addToBackStack(null);
ft.commit();
break;
case NEXT_FRAGCHAT:
FragChat fragChat = new FragChat();
ft.replace(containerId,fragChat,"fragchat");
ft.addToBackStack(null);
ft.commit();}
break;
case NEXT_FRAGLOG:
ft.replace(containerId,fragLog,"fraglog");
ft.addToBackStack(null);
ft.commit();
break;
}
Handling back in your activity:
#Override
public void onBackPressed() {
Log.d(TAG,"button back pressed");
//Check which fragment is displayed an do whatever you need
//for example like this
if (getSupportFragmentManager().findFragmentById(containerId) instanceof FragLog){
Fragment fl = getSupportFragmentManager().findFragmentByTag("fraglog");
if (fl !=null){
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.remove(fl);
ft.commit();
return;
}
}
}
Of course, this is only an example, but may be useful in Your case

Android: Check if fragment exits in Stack and reuse it

Hi I am using a Stack variable for storing the sequence of fragments clicked by the user
For example : [A,B,C,A,D]
Now I need to check if a fragment exits in the stack I need to reuse it.
From the above example I need to reuse the first element i.e, A when user clicks on the fourth time.
The problem is I have a custom keyboard opening in fragment A, now if the same fragment is in the stack as forth element the keyboard is not opening .but when I backpress and go to first element keyboard is opened in the first instance of A
Code for storing in the Stack
public void switchContent(Fragment fragment) {
if(mContent !=null && (fragment.getClass().toString().equals(mContent.getClass().toString()))){
getSlidingMenu().showContent();
return;
}
mContent = fragment;
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(R.id.content_frame, mContent);
FragmentChangeActivity.fragmentStack.lastElement().onPause();
FragmentChangeActivity.fragmentStack.push(mContent);
ft.commit();
getSlidingMenu().showContent();
}
Code for backpress
#Override
public void onBackPressed() {
if (fragmentStack.size() >= 2) {
FragmentTransaction ft = fragmentManager.beginTransaction();
fragmentStack.lastElement().onPause();
ft.remove(fragmentStack.pop());
fragmentStack.lastElement().onResume();
ft.show(fragmentStack.lastElement());
ft.commit();
} else {
super.onBackPressed();
}
}
Any help is appreciated.
The following code check's if Fragment named SearchFragment exists or not in backstack and processes accordingly. You can use this logic to determine if a specific Fragment exists or not
FragmentManager fragmentManager=getSupportFragmentManager();
Fragment currentFragment = (Fragment)fragmentManager.findFragmentById(R.id.mainContent);
if(currentFragment!=null && currentFragment instanceof SearchFragment){
//SearchFragment exists in backstack , process accordingly
}else{
//SearchFragment not present in backstack
}

Skip some fragments onBackPressed

I am fairly new with android fragments so please bear with me.
I have a bunch of fragments using a single activity as host.
In my mind, my fragments are grouped by sections although they are still modular/reusable by code.
Consider this desired scenario:
Frag1 -> (Press Next) -> Frag2 -> (Press Next) -> Frag3 -> (Press Back) -> Frag1
After going through a series of fragments, I would like to skip some previous fragments (in this scenario, skip Frag 2) on pressing the back button.
However, in my current code, my problem is that even though it goes back to Frag1, Frag3 does not disappear from the screen. What happens is that both Frag1 and Frag3 becomes visible on top of each other.
Here are my relevant code snippets:
Code snippet for creating Frag1
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
// init the fragment (with a default fragment, not null)
Fragment fragment = PlaceholderFragment.newInstance(position + 1);
// Position number from navigation sidebar starts from 0.
// Since position starts from 0, add 1 to match section number
// as implemented in {#link #onSectionAttached()}
switch(position) {
case 0:
fragment = PlaceholderFragment.newInstance(position + 1);
break;
case 1: // Frag1 case
fragment = new AddPointsFragment().newInstance(position + 1, "");
break;
default:
break;
}
// update the main content by replacing fragments
FragmentManager fragmentManager = getFragmentManager();
// clear all fragments from previous section from the back stack
fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
// replace all currently added fragments in container and replace with the new fragment
fragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit();
}
Code snippet for creating Frag2
public void onEnterButtonFragmentInteraction(int sectionNumber, String cardNo) {
// TODO: Add point for given card number
int points = 5; //sample points
AddPointsSuccessFragment addPointsSuccessFragment =
new AddPointsSuccessFragment().newInstance(sectionNumber, cardNo, points);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, addPointsSuccessFragment)
.addToBackStack(null)
.commit();
}
Code snippet for creating Frag3
public void onOkButtonFragmentInteraction(int sectionNumber, String cardNo, int points) {
RedeemRewardFragment redeemRewardFragment =
new RedeemRewardFragment().newInstance(sectionNumber, cardNo, points);
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.container, redeemRewardFragment);
fragmentTransaction.commit();
}
My current workaround for this is by adding .addToBackStack(null) in creating Frag3 and running this code
public void onBackButtonFragmentInteraction() {
this.onBackPressed(); // simulate pressing of activity back button
FragmentManager fragmentmanager = getFragmentManager();
fragmentmanager.popBackStack(); // pop Frag2 from back stack
}
right after calling the onBackPressed() method. Unfortunately, this workaround is ugly because because there is a split-second appearance of Frag2 before going to Frag1.
So the key to your solution here is this guy:
.addToBackStack(null)
Instead of null, you can pass in a String identifier for that particular transaction -- for instance, the class name of the Fragment is what we use (although that doesn't work if you have multiple instances of the same fragment on the backstack):
.addToBackStack(Fragment1.class.getName())
Then, if you wanted to get back to Fragment1 from Fragment3, just pop using the identifier of the next fragment, and pass the INCLUSIVE flag (which means it will also pop that next fragment that you specified):
getFragmentManager().popBackStack(
Fragment2.class.getName(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
Which will play your animations as expected, but as if the fragments in between were never there. The reason I suggest to use the next fragment is because you probably don't want your first fragment transaction on the back stack.
You could try this, it should work and doesnt give a split-second delay. Its not beautiful code though, and if somebody has a better way, please post.
1.Give a tag to your fragments.
transaction.add(R.id.main_activity_container, FirstFragment, "FirstFragment");
transaction.replace(R.id.main_activity_container, Second, "SECOND");
transaction.replace(R.id.main_activity_container, Third, "THIRD");
2.Modify your onBackPressed() in your frameActivity (activity) that "houses" your fragments.
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
int lastStack = getSupportFragmentManager().getBackStackEntryCount();
try {
//If the last fragment was named/tagged "three"
if (getSupportFragmentManager().getFragments().get(lastStack).getTag().equalsIgnoreCase("THIRD")){
getSupportFragmentManager().popBackStackImmediate();
getSupportFragmentManager().popBackStackImmediate();
//Get your first fragment that you loaded in the beginning.
Fragment first = getSupportFragmentManager().findFragmentByTag("FirstFragment");
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_activity_container, first);
transaction.commit();
return;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onBackPressed();
}
When you display Frag2 use:
final FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.addToBackStack(FRAG_2);
fragmentTransaction.replace(containerID, frag2, FRAG2_TAG);
and on back press:
#Override
public void onBackPressed() {
final Frag2 frag2 = (Frag2)getSupportFragmentManager().findFragmentByTag(FRAG2_TAG);
if (frag2 != null && frag2.isVisible() && getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStackImmediate();
return;
}
}
This will prevent from frag2 to be displayed after onBackPressed() called.
Avoid using popBackStack() as this will results in frag2 lifecycle trigger (onCreate, onStart, onResume ...)

Categories

Resources