Navigation drawer back button to primary fragment

2019-08-12 04:01发布

问题:

After reading this and searching in Android documentation, I gave up and decided to ask here. I'm trying to set a back button in my Navigation Drawer so that the app will close only from the Home fragment, and any other fragment will take us back to Home. For example, if we begin at Home fragment and navigate to other fragments in the navigation drawer, when we hit the back button we will get to Home fragment, and if we hit back from Home fragment, we will exit the app.

I have tried to implement it like this:

public void onNavigationDrawerItemSelected(int position) {   
    ...
    // If the next fragment is Home, clear the backstack.
    if (frag instanceof Home) {
        getSupportFragmentManager().popBackStack();
        fragmentManager.beginTransaction().replace(R.id.container, frag)
                .commit();
    }
    // If the backstack already contains a transaction, replace the current fragment
    else if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
        fragmentManager.beginTransaction().replace(R.id.container, frag)
                .commit();
    } 
    // If the backstack is empty, insert the Home -> Fragment transaction
    else {
        fragmentManager.beginTransaction().replace(R.id.container, frag)
                .addToBackStack("").commit();
    }
    ...
}

    ...

@Override
public void onBackPressed() {

    if (drawerLayout.isDrawerOpen(Gravity.START)) {
        drawerLayout.closeDrawer(Gravity.LEFT);
    } else {
        super.onBackPressed();
        // If returning back to Home fragment, restore action bar title.
        if (getSupportFragmentManager().getBackStackEntryCount() > 0)
            onSectionAttached(0);
    }
}

The link I have attached is not working properly, and the way I implemented is not working consistently. For example, if I navigate from Home to other fragments and back to home (without pressing the back button), my fragments get overlay one another.

回答1:

I just found a way to make this work fairly easy, so I decided to post it here:

// Are we in Home fragment?
private boolean homeFrag = true;
...
@Override
public void onNavigationDrawerItemSelected(int position) {
    ...
    // Next fragment is Home?
    if (frag instanceof Home)
        homeFrag = true;
    else
        homeFrag = false;

    fragmentManager.beginTransaction().replace(R.id.container, frag)
            .commit();
    onSectionAttached(position);
}
...
@Override
public void onBackPressed() {
    // Close navigation drawer if open
    if (drawerLayout.isDrawerOpen(Gravity.START)) {
        drawerLayout.closeDrawer(Gravity.LEFT);
    } else {
        // If not in Home, move back to Home.
        if (!homeFrag) {
            onNavigationDrawerItemSelected(0);
        } else
            super.onBackPressed();
    }
}

I would like to hear your thoughts about this solution.



回答2:

I think your call to super.onBackPressed() in method onBackPressed should be the last code in the else block. The reason is that the method call may affect the count in getBackStackEntryCount(). And there are already too many of these calls in my opinion.



回答3:

I've made this method taht manage fragment and backstack for you.

/**
 * Change the current displayed fragment managing fragment backstack
 * 
 * @param frag the fragment to display
 * @param saveInBackstack true if you want the previous to be in backstack
 */
private void changeFragment(Fragment frag, boolean saveInBackstack) {
    String backStateName = ((Object) frag).getClass().getName();

    try {
        FragmentManager manager = getSupportFragmentManager();
        boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);

        if (!fragmentPopped && manager.findFragmentByTag(backStateName) == null) { //fragment not in back stack, create it.
            FragmentTransaction transaction = manager.beginTransaction();
            transaction.replace(R.id.main_fragment_container, frag, ((Object) frag).getClass().getName());

            if (saveInBackstack) {
                Log.d(TAG, "Change Fragment : addToBackTack");
                transaction.addToBackStack(backStateName);
            } else {
                Log.d(TAG, "Change Fragment : NO addToBackTack");
            }

            transaction.commit();
        } else {
            Log.d(TAG, "Change Fragment : nothing to do");
            // custom effect if fragment is already instanciated
        }
    } catch (IllegalStateException exception) {
        Log.e(TAG, "Unable to commit fragment, could be activity as been killed in background. " + exception.toString());
    }
}

Also in your activity, Override onBackPressed :

@Override
public void onBackPressed() {
    int fragments = getFragmentManager().getBackStackEntryCount();
    if (fragments == 1) {
        finish();
    }
    super.onBackPressed();
}