0

okay i know there are other questions that on first glance make this one look like a duplicate, but none of these answers work in my case,

What i want is the first fragment displayed to be like a Main Activity in respect to how the back button works, i need whichever fragment i choose from my navigation drawer to go back to the first fragment when the back button is pressed then a user would quit the app by pressing it again.

So ive tried using addToBackStack and when i move to another fragment if i press the back button it comes back to my first fragment (exactly as i want) but pressing the back button again leaves me with a white screen (i wonder if this is due to the transaction animation im using which ive included below) so to get around this i tried overriding the back button and throwing in a call to finish(); but this causes whichever fragment im in to finish instead of going back to the first fragment, ive tried a handful of workarounds from the above mentioned link and many others but cannot find a decent fix any suggestions?

here is my Main Activity displayView

 private void displayView(int position) {
    // update the main content by replacing fragments
    Fragment fragment = null;

    switch (position) {
        case 0:
            fragment = new FirstFragment();

            break;

        case 1:
            fragment = new glideFrag();
            break;
        case 2:
            fragment = new secondGlideFrag();
            break;
        case 3:
            fragment = new thirdGlideFrag();
            break;
        case 4:
            fragment = new forthGlideFrag();
            break;

        case 5:
            fragment = new lgFrag();
            break;
        case 6:
            fragment = new cyanFrag();
            break;
        case 7:
            fragment = new sonyFrag();
            break;
        case 8:
            fragment = new SecondFragment();
            break;

        default:
            break;
    }

    if (fragment != null) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        fragmentTransaction.setCustomAnimations(R.anim.enter,R.anim.exit,R.anim.pop_enter,R.anim.pop_exit);

        //fragmentManager.beginTransaction()
                fragmentTransaction.replace(R.id.frame_container, fragment).addToBackStack("first Fragment").commit();

        // update selected item and title, then close the drawer
        mDrawerList.setItemChecked(position, true);
        mDrawerList.setSelection(position);
        setTitle(navMenuTitles[position]);
        mDrawerLayout.closeDrawer(mDrawerList);
    } else {
        // error in creating fragment
        Log.e("MainActivity", "Error in creating fragment");
    }

i found this that looks like a great way around it

private boolean popNext = false;

  if(popNext){
        if(position == INITIAL_POSITION){
            onBackPressed();
            mDrawerLayout.closeDrawer(mDrawerList);
            popNext = false;
            return;
        }
        getSupportFragmentManager().popBackStackImmediate();
    }
    else{
        if(position == INITIAL_POSITION){
            mDrawerLayout.closeDrawer(mDrawerList);
            return;
        }
        popNext=true;
    }

but im still fairly new to android and im not sure what to set INITIAL_POSITION to, I tried

private static final INITIAL_POSITION = 0; 

but without any luck

Community
  • 1
  • 1
Martin Seal
  • 616
  • 2
  • 14
  • 32

3 Answers3

3

When adding the initial fragment, you must not add it to the back stack. You must only do it for the next ones. When the back stack will be empty, the Activity will just finish.

Edit: Here is an explanation of the problem so you can figure out how to fix it:

Each time you add a fragment transaction to the back stack, you allow the user to revert it by pressing the back button and the Activity will return to the state it was before the transaction. If the initial fragment is added to the back stack, then when the user press back, the screen becomes blank, because there was nothing displayed before you added the initial fragment. That's why the initial fragment transaction which adds the first visible fragment to your Activity must not be added to the back stack. Usually you initialize the initial fragment like this:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if(savedInstanceState == null) {
        Fragment fragment = new FirstFragment();
        getSupportFragmentManager().beginTransaction()
            .add(R.id.frame_container, fragment)
            .commit();
    }
}
BladeCoder
  • 12,779
  • 3
  • 59
  • 51
  • so in this instance where I have all the fragments in the navigation drawer where would I call my first add to backstack? Should I instead be overriding onBackPress and calling the activity, or is there a popstack method I could call? – Martin Seal Jul 28 '15 at 20:15
  • 1
    You don't need to override anything. By default, when you press back, the system will try these in order: 1) close the drawer if it's open. 2) Pop the fragment back stack if it's not empty. 3) Finish the Activity. – BladeCoder Jul 28 '15 at 20:22
  • I wish it did my app loads fragment A when it starts if I change to fragment B or C from the navigation drawer and then press back the app exits I want it to go back to fragment A – Martin Seal Jul 28 '15 at 20:28
  • 1
    You need to *not* add A to back stack, but you *must* still add B and C to back stack. Pressing back will pop the back stack if not empty. – BladeCoder Jul 28 '15 at 20:33
  • I appreciate your trying to help me but have you looked at my code? Aren't I using the same method to call the fragments how would I differentiate between a, b, or c when there all called in the same way? – Martin Seal Jul 28 '15 at 20:48
  • 2
    That was my point, you should not initialize A using that code. You should add special code to add A in `onCreate()`, when `savedInstanceState` is null, and not add this initial transaction to the back stack. Then you may reuse your current code for the following transactions. I don't know how to explain it better. – BladeCoder Jul 28 '15 at 21:58
  • 1
    I added a more detailed explanation of your problem in my answer. – BladeCoder Jul 28 '15 at 22:30
  • I did this and the backstack takes me to the right place but still when I hit back at the first fragment (where i ezpect it to exit) I get a white screen between my styled action bar and navigation bar, – Martin Seal Jul 28 '15 at 22:54
0

BladeCoders answer was more trying to tell me how the backstack works rather than answering my question, i ended up not adding any fragments to the back stack, .addToBackStack(null), and overriding back button in MainActivity, feels like a little bit of a hack but works perfectly

@Override
public void onBackPressed() {
    FragmentManager fragmentManager = getSupportFragmentManager();

if (fragmentManager.getBackStackEntryCount() < 1){
        Fragment fragment = new FirstFragment();
        FragmentTransaction fragmentTransaction =    
        getSupportFragmentManager().beginTransaction();
        fragmentTransaction.setCustomAnimations(R.anim.enter, R.anim.exit, 
        R.anim.pop_enter, R.anim.pop_exit);

        getSupportActionBar().setTitle(mDrawerTitle);

        fragmentTransaction.replace(R.id.frame_container, 
        fragment).addToBackStack("first").commit();

    }else{
        finish();
    }
}
Martin Seal
  • 616
  • 2
  • 14
  • 32
  • 1
    For the record, `.addToBackStack(null)` still adds the transaction to the back stack, it's just not associated with a tag. And yes your solution is indeed an unnecessary hack. – BladeCoder Jul 29 '15 at 16:23
  • 1
    Also, if you want the ActionBar title to be in sync with the currently displayed fragment, you can set a backstack listener using `FragmentManager.addOnBackStackChangedListener()` and change the title there. – BladeCoder Jul 29 '15 at 16:28
-2

You can do it even with out backstack its just my point of view to simplify so that it can help some one.

 @Override
public void onBackPressed(){

    Fragment f = getSupportFragmentManager().findFragmentById(R.id.container_body);
    if(f.getClass().getName().equals(HomeFragment.class.getName())){ // here HomeFragment.class.getName() means from which faragment you actually want to exit
        finish();
    }else{
        displayView(0);  //were you want to go when back button is pressed
    }

}





private void displayView(int position) {
    Fragment fragment = null;
    String title = getString(R.string.app_name);
    switch (position) {
        case 0:
            fragment = new HomeFragment();
            title = getString(R.string.app_name);
            break;
        case 1:
            fragment = new OffersFragment();
            title = getString(R.string.nav_item_offers);
            break;
        case 2:
            fragment = new NotificationFragment();
            title = getString(R.string.nav_item_notifications);
            break;

        default:
            break;
    }

    if (fragment != null) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.container_body, fragment);
        fragmentTransaction.commit();

        // set the toolbar title
        getSupportActionBar().setTitle(title);
    }
}
nakul
  • 85
  • 5