嵌套片段和后退栈

19

在 Android 中,返回栈是否支持与嵌套的 Fragment 交互?如果支持,那么我做错了什么?在我的实现中,返回按钮完全忽略了我将此事务添加到返回栈的事实。我希望这不是由于嵌套片段的问题,只是我做错了一些事情。

以下代码位于我的一个片段内部,并用于使用新片段替换当前显示的任何嵌套片段:

     MyFragment fragment = new MyFragment();
     FragmentTransaction ft = getChildFragmentManager().beginTransaction();
     ft.setCustomAnimations(R.animator.slide_in_from_right, R.animator.slide_out_left, R.animator.slide_in_from_left, R.animator.slide_out_right);
     ft.addToBackStack(null);
     ft.replace(R.id.myFragmentHolder, fragment);
     ft.commit();

任何看到这篇帖子的人都可以看一下另一个链接:https://dev59.com/cOo6XIcBkEYKwwoYOR4q,那里解释得更好。 - lcn
4个回答

30

我有同样的问题,我想要嵌套片段,并为每个嵌套的片段保留后退堆栈。

但是...似乎v4支持库没有处理这种情况。在库中的FragmentActivity代码中,我可以找到:

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

mFragments表示活动的FragmentManager,但看起来该管理器不会将“弹出”传播到子管理器。解决方法是在从FragmentActivity继承的活动中手动调用子管理器的popBackStackImmediate(),例如:

private Fragment myFragmentContainer;

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

也许有更好的、更自动化的方法,但对我的需求来说这样就可以了。


这似乎不起作用。首先,片段没有popBackStackImmediate()方法(只有FragmentManagers有)。我尝试替换this.getFragmentManager().popBackStackImmediate(),但基本上没有看到任何不同于已经发生的事情。 - MikeS
1
在使用您提供的内容后,我已经找到了解决方案!我将编辑您的回复以包含解决方案,并将其标记为已接受,因为您让我走向了正确答案的大部分路程... - MikeS
哎呀,我的评论一点意义都没有...popBackStackImmediate必须在片段容器的子片段管理器上调用...对于这个破事我很抱歉!当然,还必须在子管理器上进行"add"操作... - la_urre
在我看来,在进行了一些调试后,发现当您尝试调用childFragmentManager时,它是null的,因此会创建一个新的FragmentManager,它已经失去了先前的状态。因此,childFragmentManager的BackStack为空,并且所调用的方法将返回false。 - mitch000001

4
API 26开始,FragmentTransaction中有一个setPrimaryNavigationFragment方法,可用于

将此FragmentManager中的当前活动片段设置为主要导航片段。

这意味着

首先调用主要导航片段的子FragmentManager来处理委托的导航操作,例如FragmentManager.popBackStack()(如果未提供ID或事务名称以弹出)。在片段系统之外的导航操作可能会选择将这些操作委托给由FragmentManager.getPrimaryNavigationFragment()返回的主要导航片段。

正如@la_urre在接受的答案中提到的,并且您可以在FragmentActivity的源代码中看到,FragmentActivityonBackPressed将调用其FragmentManagerpopBackStackImmediate(),然后检查是否存在(我假设是主要导航)片段,获取其子片段管理器并弹出其回退堆栈。

4

在我的当前项目中,我们有多个“嵌套层”,因此我想出了以下解决方法,仅针对顶级片段管理器自动弹出回退栈:

@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);
    }
}

-3
@Override
public void onBackPressed() {
    FragmentManager fm = getSupportFragmentManager();
    if (fm.getBackStackEntryCount() > 0) {
        fm.popBackStack();
        return;
    }
    finish();
}

请在您的答案中添加一些解释。 - DontVoteMeDown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接