从片段管理器中删除旧片段

81

我正在尝试学习在安卓中如何使用 Fragment。 当新的 Fragment 调用时,我正在尝试移除旧的 Fragment

7个回答

192

你需要找到现有Fragment的引用,并使用以下代码删除该fragment。你需要使用一个标签ex. "TAG_FRAGMENT"来添加/提交fragment。

Fragment fragment = getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if(fragment != null)
    getSupportFragmentManager().beginTransaction().remove(fragment).commit();

就是这样。


片段是否也不使用堆栈机制? 或者只有在使用后退堆栈时才会出现? 或者这种技术是将片段移到顶部,然后删除片段并将片段放回原处,还是其他什么? - Sreekanth Karumanaghat
@SreekanthKarumanaghat:是的,您可以使用pop back stack。但它将从上下文中删除最顶部的片段。但是,如果您想从容器中删除特定的片段,则可以使用remove方法。 - Yashdeep Patel
我的问题是这个方法是如何工作的?我对Fragment的工作原理的理解正确吗? Fragment 1 -> Fragment 2 -> Fragment 3这是否意味着Fragments被保存在一个堆栈中,还是后退堆栈只是作为一种自定义机制维护的? - Sreekanth Karumanaghat
@SreekanthKarumanaghat 是的,Fragment可以在堆栈中维护。但是为此,您需要告诉片段管理器将它们添加到堆栈中。请参考:https://developer.android.com/reference/android/app/FragmentTransaction.html#addToBackStack(java.lang.String)。 - Yashdeep Patel
只是想补充一下,通过提交调度,它将在下一个运行循环中执行。如果您需要立即删除它,可以调用 fragmentManager.executePendingTransactions() - Toland Hon

10

我曾经遇到过同样的问题。我想出了一个简单的解决方法。使用代码片段 .replace 而不是代码片段.add。用替换代码片段的方法实现的效果和添加代码片段然后手动移除它的效果是一样的。

getFragmentManager().beginTransaction().replace(fragment).commit();

而不是

getFragmentManager().beginTransaction().add(fragment).commit();

9

我曾遇到类似的问题,需要移除旧的片段。最终我清除了包含这些片段的布局。

LinearLayout layout = (LinearLayout) a.findViewById(R.id.layoutDeviceList);
layout.removeAllViewsInLayout();
FragmentTransaction ft = getFragmentManager().beginTransaction();
...

我不知道这是否会导致泄漏,但对我来说它是有效的。


这实际上是一种很好的方法。 - Droid Chris
但这将删除包含在 XML 中并通过其 ID 在程序中使用的片段,以替换片段。 - Prabs
4
这只是从布局中移除了碎片的视图,而该碎片本身仍附加在碎片管理器上,并未停止、分离或销毁。 - Subaru Tashiro
完美的解决方案,用于移除在布局中以编程方式添加的视图! - Michaël Randria

2

可能您的应用程序中存在旧的Fragment实例,它会保留一个引用。请参阅这篇有趣的文章:Android内存泄漏-识别、处理和避免

如果您使用了addToBackStack方法,则会保留对该Fragment实例的引用,从而避免垃圾收集器清除该实例。该实例将保留在FragmentManager的Fragment列表中。您可以通过以下代码查看该列表:

ArrayList<Fragment> fragmentList = fragmentManager.getFragments();

下面的代码不是最佳解决方案(因为不会删除旧的Fragment实例以避免内存泄漏),但可以从FragmentManager的Fragment列表中删除旧的Fragment实例:

int index = fragmentManager.getFragments().indexOf(oldFragment);
fragmentManager.getFragments().set(index, null);

您不能从arrayList中删除条目,因为FragmentManager明显使用索引ArrayList来获取fragment。

我通常使用以下代码与fragmentManager一起使用

public void replaceFragment(Fragment fragment, Bundle bundle) {

    if (bundle != null)
        fragment.setArguments(bundle);

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    Fragment oldFragment = fragmentManager.findFragmentByTag(fragment.getClass().getName());

    //if oldFragment already exits in fragmentManager use it
    if (oldFragment != null) {
        fragment = oldFragment;
    }

    fragmentTransaction.replace(R.id.frame_content_main, fragment, fragment.getClass().getName());

    fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);

    fragmentTransaction.commit();
}

1

我在处理返回键(onBackPress)时遇到了碎片(fragment)的问题。我不想返回旧的碎片。

这个解决方案可以帮助我从碎片管理器中删除旧的碎片:

FragmentManager fm = getSupportFragmentManager();
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

您可以像下面这样使用if块:
FragmentManager fm = getSupportFragmentManager();

if (fm.getBackStackEntryCount() > 0) {
    fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

0

我在几个视图中遇到了同样的错误,所以我将冗余视图的可见性设置为GONE。这种方法解决了我的问题。

<View>.setVisibility(View.GONE); 

-1

In Kotlin

  val fragList  = f.supportFragmentManager.fragments
    for (fragment in fragList) {
        f.supportFragmentManager.beginTransaction().remove(fragment).commit()
    }

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