Nested Fragments and The Back Stack

∥☆過路亽.° 提交于 2019-11-28 20:36:25

I have the same problem, I would like to nest fragments, and to keep a back stack for each nested fragment.

But... it seems that this case is not handled by the v4 support library. In the FragmentActivity code in the library, I can find :

public void onBackPressed() {
    if (!mFragments.popBackStackImmediate()) {
        finish();
    }
}

The mFragments represents the FragmentManager of the activity, but it does not seem this manager "propagates" the pop to children managers. A workaround would be to manually call the popBackStackImmediate() on the child manager, like this in the activity inherited from FragmentActivity :

private Fragment myFragmentContainer;

    @Override
    public void onBackPressed() {
            if (!myFragmentContainer.getChildFragmentManager().popBackStackImmediate()) {
                finish(); //or call the popBackStack on the container if necessary
            }
    }

There might be a better way, and a more automated way, but for my needs it is allright.

In my current project we have multiple "nested layers" so I've come up with following workaround to automatically pop backstack only for top level fragment managers:

@Override
public void onBackPressed() {
    SparseArray<FragmentManager> managers = new SparseArray<>();
    traverseManagers(getSupportFragmentManager(), managers, 0);
    if (managers.size() > 0) {
        managers.valueAt(managers.size() - 1).popBackStackImmediate();
    } else {
        super.onBackPressed();
    }
}

private void traverseManagers(FragmentManager manager, SparseArray<FragmentManager> managers, int intent) {
    if (manager.getBackStackEntryCount() > 0) {
        managers.put(intent, manager);
    }
    if (manager.getFragments() == null) {
        return;
    }
    for (Fragment fragment : manager.getFragments()) {
        if (fragment != null) traverseManagers(fragment.getChildFragmentManager(), managers, intent + 1);
    }
}

As of API 26 there is a setPrimaryNavigationFragment method in FragmentTransaction that can be used to

Set a currently active fragment in this FragmentManager as the primary navigation fragment.

This means that

The primary navigation fragment's child FragmentManager will be called first to process delegated navigation actions such as FragmentManager.popBackStack() if no ID or transaction name is provided to pop to. Navigation operations outside of the fragment system may choose to delegate those actions to the primary navigation fragment as returned by FragmentManager.getPrimaryNavigationFragment().

As mentioned by @la_urre in the accepted answer and as you can see in FragmentActivity's source, the FragmentActivity's onBackPressed would call its FragmentManager's popBackStackImmediate() which in turn would check whether there is an mPrimaryNav (primary navigation, I assume) fragment, get its child fragment manager and pop its backstack.

@Override
public void onBackPressed() {
    FragmentManager fm = getSupportFragmentManager();
    if (fm.getBackStackEntryCount() > 0) {
        fm.popBackStack();
        return;
    }
    finish();
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!