这是在离开深层嵌套堆栈时清理Fragment堆栈的正确方法吗?

PJL*_*PJL 127 android android-fragments fragment-backstack

我正在使用Android兼容性库来实现片段并扩展了布局示例,以便片段包含一个触发另一个片段的按钮.

在左侧的选择窗格中,我有5个可选项 - A B C D E.

每个都FragmentTransaction:replace在详细信息窗格中加载一个片段(via ) -a b c d e

现在我扩展了片段e以包含一个按钮,该按钮e1还会在详细信息窗格中加载另一个片段.我在片段e的onClick方法上做了这个,如下所示:

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details_frag, newFrag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
Run Code Online (Sandbox Code Playgroud)

如果我做出以下选择:

E - e - e1 - D - E
Run Code Online (Sandbox Code Playgroud)

然后片段e在详细信息窗格中.这很好,我想要的.但是,如果我back在此时按下按钮它什么都不做.我必须点击两次,因为e1它仍然在堆栈上.点击后我在onCreateView中得到一个空指针异常:

为了"解决"这个问题,无论何时A B C D E选择,我都添加了以下内容:

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
    fm.popBackStack();
}
Run Code Online (Sandbox Code Playgroud)

只是想知道这是否是正确的解决方案或我是否应该做一些不同的事情?

小智 249

那么根据预期的行为,有几种方法可以解决这个问题,但这个链接应该为您提供所有最佳解决方案,而且不出所料,来自Dianne Hackborn

http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42

基本上你有以下选择

  • 使用名称作为初始后备堆栈状态并使用 FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • 使用FragmentManager.getBackStackEntryCount()/ getBackStackEntryAt().getId() 来检索后堆栈上第一个条目的ID,以及 FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) 应该弹出整个后台堆栈...我认为这个文档是错误的.(实际上我猜它只是不包括你传入的情况POP_BACK_STACK_INCLUSIVE),

  • 声称该组被禁止为垃圾邮件,我无法访问该链接:(有没有人在其他地方有资源? (6认同)
  • 第二个为我工作.清除整个堆栈意味着什么:getSupportFragmentManager().popBackStack(getSupportFragmentManager().getBackStackEntryAt(0).getId(),FragmentManager.POP_BACK_STACK_INCLUSIVE); (4认同)

Paw*_*ari 60

如果你不想弹出所有堆栈条目,那么另一个干净的解决方案......

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_container, fragmentInstance).addToBackStack(null).commit();
Run Code Online (Sandbox Code Playgroud)

这将首先清理堆栈,然后加载一个新的片段,因此在任何给定的点上,您将只有一个片段在堆栈中


Jay*_*ker 25

感谢Joachim的回答,我使用代码最终清除所有后台堆栈条目.

// In your FragmentActivity use getSupprotFragmentManager() to get the FragmentManager.

// Clear all back stack.
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < backStackCount; i++) {

    // Get the back stack fragment id.
    int backStackId = getSupportFragmentManager().getBackStackEntryAt(i).getId();

    fm.popBackStack(backStackId, FragmentManager.POP_BACK_STACK_INCLUSIVE);

} /* end of for */
Run Code Online (Sandbox Code Playgroud)

  • 为什么在这里使用循环?对我来说FragmentManager.popBackStack(null,FragmentManager.POP_BACK_STACK_INCLUSIVE)清除了所有后台堆栈条目...... (18认同)
  • @Marek,因为有时不应该删除所有片段,所以循环适合于此. (3认同)
  • @CoolMind,这对我来说仍然没有意义。popBackStack(backStackId, INCLUSIVE) 会将所有片段(状态)弹出回 backStackId,因此一旦您弹出要弹出的最低的“i”,所有较高的片段都应该同时弹出。那么循环有什么意义呢? (2认同)

Lok*_*esh 7

我已经研究了很多清理Backstack,最后看到了Transaction BackStack及其管理.这是最适合我的解决方案.

 // CLEAR BACK STACK.
    private void clearBackStack() {
        final FragmentManager fragmentManager = getSupportFragmentManager();
        while (fragmentManager.getBackStackEntryCount() != 0) {
            fragmentManager.popBackStackImmediate();
        }
    }
Run Code Online (Sandbox Code Playgroud)

上面的方法遍历backstack中的所有事务,并一次一个地删除它们.

注意:上面的代码有时不起作用,我因为这段代码而面对ANR,所以请不要试试这个.

更新 下面的方法从backstack中删除该"name"的所有fregment.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
Run Code Online (Sandbox Code Playgroud)
  • name如果为非null,则这是要查找的先前后退状态的名称; 如果找到,将弹出所有达到该状态的状态.该
  • POP_BACK_STACK_INCLUSIVE标志可用于控制是否弹出命名状态本身.如果为null,则仅弹出顶部状态.