0

I have gone through many stackoverflow question before writing this. i am so confused about this guy Backstack in fragment.

I have Added three fragment on the same container inside an Activity

Fragment 1 :

private void addLandingFragment() {
        landingPageFragment = LandingPageFragment.newInstance();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.add( R.id.container, landingPageFragment, LANDING_PAGE_FRAGMENT_TAG );
        transaction.commit();

    }

Fragment 2 :

public void addIntrofragment() {
    fragment2 = IntroFragment.newInstance();
    FragmentTransaction transaction = manager.beginTransaction();
    transaction.replace( R.id.container, fragment2, INTRO_PAGE_FRAGMENT_TAG);
    transaction.addToBackStack(fragment2.getClass().getName() );
    transaction.commit();
}

Fragment 3 :

public void onGetStartedClicked() {
        fragment3= ConnectFragment.newInstance();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.replace( R.id.container, fragment3,CONNECT_PAGE_FRAGMENT_TAG );
        transaction.commit();
    }

Now what I want is when user presses back button on fragment 3 it should come on very first fragment so I have overrided the onBackPressed() method.

@Override
    public void onBackPressed() {
        manager.popBackStack(fragment2.getClass().getName() ,FragmentManager.POP_BACK_STACK_INCLUSIVE );

    }

but nothing happening on screen it keeps fragment 3 running.

UPDATE

When I am navigating from

fragment1 > fragment2

and presses back button on fragment2, I am coming to fragment1 but if move from

fragment1 > fragment2> fragment3

I am getting the stack entry count 1 on onBackPressed() method but on device screen it still shows fragment3. Now pressing back button again will exit me from app but fragment1 wont come on screen. So puzzling why it is happening ?

Any solution to achieve this.

Piyush Agarwal
  • 25,608
  • 8
  • 98
  • 111

2 Answers2

0

calling replace() will remove the previous fragment, Fragment 1 should be called using replace(), and Fragment 2 & 3 should be called using add(), you should also add the last transaction to back stack (calling Fragment 3)

Like this:

Fragment 1:

private void addLandingFragment() {
    landingPageFragment = LandingPageFragment.newInstance();
    FragmentTransaction transaction = manager.beginTransaction();
    transaction.replace( R.id.container, landingPageFragment, LANDING_PAGE_FRAGMENT_TAG );
    transaction.commit();

}

Fragment 2:

public void addIntrofragment() {
fragment2 = IntroFragment.newInstance();
FragmentTransaction transaction = manager.beginTransaction();
transaction .hide(LandingPageFragment.this);
transaction.add( R.id.container, fragment2, INTRO_PAGE_FRAGMENT_TAG);
transaction.addToBackStack(fragment2.getClass().getName() );
transaction.commit();

}

Fragment 3:

public void onGetStartedClicked() {
    fragment3= ConnectFragment.newInstance();
    FragmentTransaction transaction = manager.beginTransaction();
    fragmentManager.popBackStackImmediate();     // to remove fragment 2    
    transaction.add( R.id.container, fragment3,CONNECT_PAGE_FRAGMENT_TAG );
    transaction.addToBackStack(fragment3.getClass().getName() );
    transaction.commit();
}

finally your onBackPressed should be like this:

@Override
public void onBackPressed() {
    fragmentManager.popBackStackImmediate();
    fragmentTransaction.show(LandingPageFragment.this);
}

therefore your onBackPressed will always pop the top fragment on the stack (Fragment 3), and since Fragment 2 was already popped before adding Fragment 3, then onBackPressed will display the very first fragment.

Silvia H
  • 8,097
  • 7
  • 30
  • 33
  • Sorry but add will not even show the second fragment on screen, I have tried this. – Piyush Agarwal Jun 29 '15 at 15:19
  • my bad! I forgot to use show() and hide(), will edit my answer now, and yes I've tried it. – Silvia H Jun 29 '15 at 15:23
  • And one more thing fragment 1 is appearing for a while before showing the fragment 3. – Piyush Agarwal Jun 29 '15 at 15:24
  • please see my edits, I hide fragment 1 before adding fragment 2, and show it in onBackPressed(). – Silvia H Jun 29 '15 at 15:27
  • Still fragment2 is not appearing on screen, dude I am not getting how it is working for you ? – Piyush Agarwal Jun 29 '15 at 15:37
  • And i did not understand your concept of adding fragment instead of replacing fragment because it is not the fragment in backstack it is the transaction so popbackstack just only doing the reverse transaction so my code should work even with replace. – Piyush Agarwal Jun 29 '15 at 15:39
  • see the docs for replace(): Replace an existing fragment that was added to a container. This is essentially the same as calling {@link #remove(Fragment)} for all currently added fragments that were added with the same containerViewId and then {@link #add(int, Fragment, String)} with the same arguments given here. – Silvia H Jun 29 '15 at 15:41
  • by calling add() instead of replace(), fragment 1 will not be removed, therefore when you call popBackStackImmediate() which pops fragment 3, fragment 1 will remain in its previous state before hiding it. – Silvia H Jun 29 '15 at 15:43
  • Sorry for asking too many questions but I want to understand this backstack clearly. First thing your code is not working for me. With my earlier code When I go from fragment1 to fragment2 using replace and presses the back button on fragment 2, fragment1 comes on screen. Now my question is why so because as per your concept it was replaced so from where it came back ? – Piyush Agarwal Jun 29 '15 at 18:53
  • if your code works only when pressing back on fragment 2, then use popBackStackImmediate right before adding fragment 3, and don't forget to add the last transaction to back stack as well (fragment 3) – Silvia H Jun 29 '15 at 23:44
0

Thanks Silvia.H for you support. I have solved my problem and found it as the best possible solution for me.

The only mistake I did was, I did not add fragment3 in backstack

So the only changes required was

public void onGetStartedClicked() {
        fragment3= ConnectFragment.newInstance();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.replace( R.id.container, fragment3,CONNECT_PAGE_FRAGMENT_TAG );
        transaction.addToBackStack(ConnectFragment.class.getName() );
        transaction.commit();
    }

Now this makes you clear that in order to use popBackStack with name like

manager.popBackStack(fragment2.getClass().getName() ,FragmentManager.POP_BACK_STACK_INCLUSIVE );

you have to keep that transaction in backstack from where you are actually pressing the back button.

I have made one more small change in onBackPressed() method which allows the app to exist when user presses back button on fragment1.

My onBackPressed() look like this now

@Override
    public void onBackPressed() {

        if( manager.getBackStackEntryCount() > 0 ) {
            getSupportFragmentManager().popBackStack(
                    scoreTrackerIntroFragment.getClass().getName(),
                    FragmentManager.POP_BACK_STACK_INCLUSIVE );
        }else {

            super.onBackPressed();
        }

    }

Woop! Now I am clear about this "Backstack" guy.

Piyush Agarwal
  • 25,608
  • 8
  • 98
  • 111