使用碎片清除后堆栈



我将我的Android应用程序移植到了蜂窝,为了使用碎片,我进行了一次大的重构。在我以前的版本中,当我按下主页按钮时,我会执行ACTIVITY_CLEAR_TOP以重置后堆栈。

现在,我的应用程序只是一个包含多个片段的"活动",所以当我按下"主页"按钮时,我只需替换其中的一个片段。如何在不使用带有ACTIVITY_CLEAR_TOP标志的startActivity的情况下清除后堆栈?

我在这里发布了类似的内容

来自Joachim的回答,来自Dianne Hackborn:

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

我最终只使用了:

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {    
    fm.popBackStack();
}

但同样可以使用类似的东西:

((AppCompatActivity)getContext()).getSupportFragmentManager().popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)

这将弹出所有状态,直到命名状态为止。然后,您可以用您想要的替换片段

来回答@Warpzit的评论,让其他人更容易找到。

用途:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

尊重所有相关方;我很惊讶地看到你们中有多少人可以用一个简单的清除整个碎片堆栈

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

根据Android文档(关于name论点——声称的工作提案中的"null")。

如果为空,则仅弹出顶部状态

现在,我确实意识到我对你的特定实现缺乏了解(比如在给定的时间点你在后堆栈中有多少条目),但当我期望在更广泛的设备和供应商上有一个定义良好的行为时,我会把所有的钱都押在公认的答案上:

(供参考,与此相关)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}

清除无循环的后台

String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);

其中name是addToBackStack()参数

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)

适用于我,不使用循环的简单方法:

 FragmentManager fragmentManager = getSupportFragmentManager();
 //this will clear the back stack and displays no animation on the screen
 fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

接受的答案对我来说不够。我不得不使用:

FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
    fm.popBackStackImmediate();
}

Hi~我找到了一个更好的解决方案,来自:https://gist.github.com/ikew0ng/8297033

    /**
 * Remove all entries from the backStack of this fragmentManager.
 *
 * @param fragmentManager the fragmentManager to clear.
 */
private void clearBackStack(FragmentManager fragmentManager) {
    if (fragmentManager.getBackStackEntryCount() > 0) {
        FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
        fragmentManager.popBackStack(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }
}

我只想添加:--

使用以下从背面弹出

fragmentManager.popBackStack()

只是从事务中删除片段,而不是从屏幕中删除片段。因此,理想情况下,它可能对您不可见,但可能有两个或三个碎片堆叠在一起,按反键时,UI可能看起来杂乱无章。

举个简单的例子:-

假设您有一个fragmentA,它使用fragmentmanager.replace()加载Fragmnet B,然后我们添加ToBackStack来保存此事务。所以流程是:--

步骤1->片段A->片段B(我们移到片段B,但片段A在背景中,不可见)。

现在,您在fragmentB中做一些工作,然后按下Save按钮——保存后,该按钮应返回fragmentA。

步骤2->保存片段B后,我们返回片段A。

步骤3->所以常见的错误是…在片段B中,我们将用片段A来执行片段Manager.replacement()片段B。

但实际发生的事情是,我们再次加载片段A,取代片段B。现在有两个片段A(一个来自步骤1,一个来自这个步骤3)。

FragmentsA的两个实例堆叠在一起,可能看不见,但它就在那里。

因此,即使我们通过上述方法清除后台,事务也会被清除,但不会清除实际的片段。因此,理想情况下,在这种特殊情况下,按下保存按钮后,只需执行fm.popBackStack()fm.popBackImmediate()可返回片段a。

因此,正确的Step3->fm.popBackStack()返回到内存中已经存在的fragmentA。

对于这里的科特林人:

repeat(supportFragmentManager.backStackEntryCount) {
    supportFragmentManager.popBackStack()
}

阅读文档并研究片段id是什么,它似乎只是堆栈索引,因此这很有效:

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

零(0)是堆栈的底部,因此弹出到它(包括它)会清除堆栈。

CAVEAT:虽然上面的内容在我的程序中有效,但我有点犹豫,因为FragmentManager文档从未实际说明id是堆栈索引。这是有道理的,我所有的调试日志都表明了这一点,但在某些特殊情况下可能不会?有人能以这样或那样的方式证实这一点吗?如果是的话,那么以上就是最好的解决方案。如果没有,这是另一种选择:

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }

只需使用此方法并传递Context&片段标签,我们需要删除背景片段。

用法

clearFragmentByTag(context, FragmentName.class.getName());

public static void clearFragmentByTag(Context context, String tag) {
    try {
        FragmentManager fm = ((AppCompatActivity) context).getSupportFragmentManager();
        for (int i = fm.getBackStackEntryCount() - 1; i >= 0; i--) {
            String backEntry = fm.getBackStackEntryAt(i).getName();
            if (backEntry.equals(tag)) {
                break;
            } else {
                 fm.popBackStack();
            }
        }
    } catch (Exception e) {
        System.out.print("!====Popbackstack error : " + e);
        e.printStackTrace();
    }
}

它对我有效,试试这个:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }

我是这样做的:

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}
    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

调用这个方法会非常巧妙。

  1. 无需环路
  2. 如果在片段中使用动画,它将不会显示太多动画。但使用循环会
private boolean removeFragFromBackStack() {
    try {
        FragmentManager manager = getSupportFragmentManager();
        List<Fragment> fragsList = manager.getFragments();
        if (fragsList.size() == 0) {
            return true;
        }
        manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

最新更新