Handling fragment backstack in Navigation drawer

2019-09-05 01:40发布

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

3条回答
别忘想泡老子
2楼-- · 2019-09-05 01:52

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();
    }
}
查看更多
叛逆
3楼-- · 2019-09-05 01:58

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();
    }
}
查看更多
倾城 Initia
4楼-- · 2019-09-05 02:12

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);
    }
}
查看更多
登录 后发表回答