148

我想知道这是否实际上是Android API中的一个错误:

我有这样的设置:

┌----┬---------┐
|    |         |
|  1 |    2    |
|    |┌-------┐|
|    ||       ||
|    ||   3   ||
└----┴┴-------┴┘
  1. 是一个在右窗格中加载片段 #2(搜索屏幕)的菜单。
  2. 是一个搜索屏幕,其中包含片段#3,它是一个结果列表。
  3. 结果列表在多个地方使用(包括作为一个功能强大的高级片段本身)。

此功能在手机上运行良好(其中 1 & 2 和 3 是ActivityFragments)。

但是,当我使用此代码时:

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();       
    Fragment frag = new FragmentNumber2();
    if(toLoad != null) frag.setArguments(toLoad);
    transaction.replace(R.id.rightPane, frag);      
    transaction.commit();

水平线性布局中的whereR.id.leftPaneR.id.rightPaneare <fragment>

据我了解,上面的代码删除了常驻的片段,然后用新的片段替换它。太棒了...显然这不是发生的情况,因为当此代码第二次运行时,您会收到以下异常:

07-27 15:22:55.940: ERROR/AndroidRuntime(8105): Caused by: java.lang.IllegalArgumentException: Binary XML file line #57: Duplicate id 0x7f080024, tag null, or parent id 0x0 with another fragment for FragmentNumber3

这是因为 FragmentNumber3 的容器已复制并且不再具有唯一 ID。在添加新的 Fragment 之前,最初的 Fragment 没有被销毁(?)(在我看来,这意味着它没有被替换)。

有人可以告诉我这是否可能(这个答案表明它不是)还是一个错误?

4

6 回答 6

204

当前不支持嵌套片段。试图将一个片段放在另一个片段的 UI 中会导致未定义且可能会损坏的行为。

更新:从 Android 4.2(和 Android 支持库 rev 11)开始支持嵌套片段:http: //developer.android.com/about/versions/android-4.2.html#NestedFragments

注意(根据this docs):“注意:当布局包含时,您不能将布局膨胀到片段中<fragment>。嵌套片段仅在动态添加到片段时才受支持。

于 2011-07-27T16:17:37.010 回答
98

android 4.2 及更高版本支持嵌套片段

Android支持库现在还支持嵌套片段,因此您可以在 Android 1.6 及更高版本上实现嵌套片段设计。

要嵌套片段,只需在要添加片段的片段上调用​​getChildFragmentManager() 。这将返回一个 FragmentManager,您可以像通常从顶级活动中一样使用它来创建片段事务。例如,下面是一些从现有 Fragment 类中添加片段的代码:

Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();

要了解有关嵌套片段的更多信息,请阅读这些教程
第 1
部分第 2
部分第 3 部分

这是一篇 SO 帖子,讨论了嵌套片段的最佳实践

于 2012-06-13T17:51:14.487 回答
34

..您可以在父片段的destroyview方法中清理嵌套片段:

@Override
    public void onDestroyView() {

      try{
        FragmentTransaction transaction = getSupportFragmentManager()
                .beginTransaction();

        transaction.remove(nestedFragment);

        transaction.commit();
      }catch(Exception e){
      }

        super.onDestroyView();
    }
于 2011-10-31T12:37:13.917 回答
14

我有一个正在开发的应用程序,它的布局类似于启动片段的操作栏中的选项卡,其中一些片段中有多个嵌入的片段。

当我尝试运行应用程序时,我遇到了同样的错误。似乎如果在取消选择选项卡然后重新选择后在 xml 布局中实例化片段,我会收到充气机错误。

我解决了这个问题,用 Linearlayouts 替换 xml 中的所有片段,然后使用片段管理器/片段事务来实例化片段,一切似乎至少在测试级别上正常工作。

我希望这能够帮到你。

于 2011-10-26T15:34:53.103 回答
4

我遇到了同样的问题,已经为此苦苦挣扎了几天,应该说最简单的解决方法是在选择/取消选择选项卡时使用 fragment.hide() / fragment.show() ()。

public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft)
{
    if (mFragment != null)
        ft.hide(mFragment);
}

当屏幕旋转发生时,所有父片段和子片段都会被正确销毁。

这种方法还有一个额外的优势——使用 hide()/show() 不会导致片段视图失去它们的状态,因此不需要为 ScrollViews 恢复之前的滚动位置。

问题是我不知道当它们不可见时不分离碎片是否正确。我认为 TabListener 的官方示例在设计时考虑到片段是可重用的,你不应该用它们污染内存,但是,我认为如果你只有几个选项卡并且你知道用户会经常在它们之间切换它将适合使它们与当前活动保持联系。

我想听听更有经验的开发者的意见。

于 2012-07-19T11:28:23.727 回答
0

如果您发现您的嵌套片段没有被删除或被复制(例如,在 Activity 重新启动时,在屏幕旋转时)尝试更改:

transaction.add(R.id.placeholder, newFragment);

transaction.replace(R.id.placeholder, newFragment);

如果以上没有帮助,请尝试:

Fragment f = getChildFragmentManager().findFragmentById(R.id.placeholder);

FragmentTransaction transaction = getChildFragmentManager().beginTransaction();

if (f == null) {
    Log.d(TAG, "onCreateView: fragment doesn't exist");
    newFragment= new MyFragmentType();
    transaction.add(R.id.placeholder, newFragment);
} else {
    Log.d(TAG, "onCreateView: fragment already exists");
    transaction.replace(R.id.placeholder, f);
}
transaction.commit();

在这里学习

于 2016-06-19T14:10:27.837 回答