防止同一片段多次堆叠 (addToBackStack)

Posted

技术标签:

【中文标题】防止同一片段多次堆叠 (addToBackStack)【英文标题】:Prevent The Same Fragment From Stacking More Than Once ( addToBackStack) 【发布时间】:2016-02-18 22:17:19 【问题描述】:

我有一个Activity,其中包含三个片段,我们称它们为 ABCFragment A 在 Activity onCreate() 中被调用。

FragmentA fragA = new FragmentA();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(R.id.activity2_layout, fragA, "A");
transaction.commit();

当按下某些按钮时,会被 Fragment BC 替换,并且 FragmentTransaction 调用addToBackStack()

FragmentB fragB = new FragmentB(); //or C
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.activity2_layout, fragB, "B");  //or C
transaction.addToBackStack("B"); //or C
transaction.commit();

但是假设我连续三次调用Fragment B,我怎样才能防止它自己堆叠呢?同时我希望这成为可能: B 被调用 > C 被调用 > B 被调用 - 但是当我试图回去时,我希望 B 只打开一次 (C B) 而不是 (B C B)。所以基本上用新的 backStack 删除第一个 backStack。

【问题讨论】:

【参考方案1】:

来自How to resume Fragment from BackStack if exists,可能与您的查询非常相似。

有一种方法可以根据事务名称或提交提供的 id 弹出回栈(例如,使用 Fragment 的类名作为 Thijs 已经提到):

String backStateName = fragment.getClass().getName();

添加到后台堆栈:

FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();

弹出时:

getSupportFragmentManager().popBackStackImmediate (backStateName, 0); 

所以在替换fragment之前,我们可以像这样检查backstack中的存在:

boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0);

if (!fragmentPopped) //fragment not in back stack, create it.
    ...
    ...
    ft.addToBackStack(backStateName);
    ft.commit();

请检查上述问题和接受的答案以获得更多解释。

【讨论】:

这是更好的答案,因为它回答了这两个问题:)【参考方案2】:

我刚刚在我自己的一个项目中解决了您的一个问题,即how can I prevent it from stacking on to it self?。这是我在那里使用的确切代码:

public void setContent(@NonNull Fragment fragment, boolean addToBackStack) 
    Fragment current = getSupportFragmentManager().findFragmentById(R.id.main_content);
    if (current == null || !current.getClass().equals(fragment.getClass())) 
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if (addToBackStack) 
            transaction.addToBackStack(null).add(R.id.main_content, fragment).commit();
         else 
            transaction.replace(R.id.main_content, fragment).commit();
        
    

此代码的作用是检查当前显示的 Fragment 是什么类,并将其与要替换它的 Fragment 进行比较。如果它们相同,它不会做任何事情。此代码可以按照您的需要进行调整

Fragment newFragment = new FragmentB(); //OR FragmentC
Fragment current = getSupportFragmentManager().findFragmentById(R.id.activity2_layout);
if (!current.getClass().equals(newFragment.getClass())) 

    //POP BACKSTACK HERE LIKE EXPLAINED BELOW

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    final String tag = newFragment.getClass().getSimpleName();
    transaction.addToBackStack(tag);
    transaction.add(R.id.activity2_layout, newFragment, tag);
    transaction.commit();
 else 
    //THROW AN ERROR OR SOMETHING, HANDLE IT BEING THE SAME

确保一次只存在一个特定类型的片段可能可以通过在第一次出现相同片段之前弹出回栈来实现。我没有为此编写任何代码,但实现该功能应该不会太难。如果您自己无法弄清楚,请告诉我,我会尝试为您写一个示例:)

【讨论】:

谢谢 :) 不需要示例 :) 我现在唯一需要弄清楚的是如何删除已经制作的 backStacks,如果它甚至可能的话,因为我找不到任何相关的文档或示例。 我认为这根本不可能。据我所知,FragmentManager 有一个且只有一个后栈。您可以弹出条目,然后添加另一个条目以用一个新条目“替换”该数量的条目。只要你在commit() 之前这样做,你应该没问题:) @IvanJavorovic by remove backStacks 你的意思是清除后台堆栈吗?

以上是关于防止同一片段多次堆叠 (addToBackStack)的主要内容,如果未能解决你的问题,请参考以下文章

如何多次使用同一个片段?

防止导航到同一个片段

防止多次点击同一个 UIButton

如何防止部分视图中的脚本多次加载并在同一页面中多次使用部分时导致错误

我如何调整这个选择语句以防止它多次从同一个表中选择?

防止同一帐户多次登录(桌面应用程序)