片段中的片段


145

我想知道这是否真的是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();

其中R.id.leftPaneR.id.rightPane<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。在添加新片段之前,初始片段尚未销毁(?)(我认为这意味着尚未替换)。

有人可以告诉我这是否可行(此答案表明不是)还是错误?



6
@rds这是一个古老的问题,毫无意义地标记为重复。
pietv8x

Answers:


203

目前不支持嵌套片段。尝试将一个片段放在另一个片段的UI中会导致未定义的行为,并且很可能会破坏行为。

更新:嵌套片段支持由于Android 4.2(和Android支持库修订版11):http://developer.android.com/about/versions/android-4.2.html#NestedFragments

注意(按照本文档):“ 注意:当布局包含时,您不能将布局充气为片段<fragment>。仅当动态添加到片段时才支持嵌套片段。


14
不支持,因为它不是初始实现的设计目标。我听说过对此功能的要求很高,所以它可能会在某个时候完成,但是像往常一样,还有很多其他事情与它竞争。
Hackbod 2011年

4
我通过扩展FragmentActivity,FragmentManager和FragmentTransaction来进行管理。基本前提是在我的活动中扩展DeferringFragmentActivity,提供相同的api,因此没有其他代码更改。当我调用getFragmentManager时,我得到一个DeferringFragmentManager实例,当我调用beginTransaction时,我得到了DeferredTransaction。此事务存储具有调用的方法和参数的POJO。调用commit时,我们首先查找所有未决的DeferredTransactions。提交所有事务后,我们将启动实际事务并使用args运行所有存储的方法。
dskinner

11
到此为止。嵌套Fragments现在已经成为Android API的一部分了!developer.android.com/about/versions/…
Alex Lockwood

9
哇,真是一场噩梦:如果您在Fragment上使用<fragment>,并且该Fragment恰好使用了子片段,那么它不会因明确的错误而失败(“不能将子片段添加到布局片段中”)-神秘失败,但出现“片段未创建视图”之类的例外。调试需要花费数小时的时间……
Glenn Maynard 2013年

6
@MartínMarconcini可以肯定,但是基于API提供的功能,这一点都不明显。如果不允许某些事情,则应将其明确记录在案,不要让开发人员掏腰包,因为某些事情无法按您期望的方式工作。
dcow

98

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

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

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

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

要了解有关嵌套片段的更多信息,请仔细阅读以下教程:
第1
部分第2
部分第3部分

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


Nestedfragment的主要缺点是我们无法从childfragment中调用optionmenu :(如果我们使用的是ABS!
LOG_TAG 2013年

你能看看我的问题吗?它非常相似..stackoverflow.com/ questions/32240138/…。对我而言,儿童framnet不会因代码而膨胀
Nicks

33

..您可以使用父片段的destroyview方法清除嵌套片段:

@Override
    public void onDestroyView() {

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

        transaction.remove(nestedFragment);

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

        super.onDestroyView();
    }

4
如果您使用SetAlwaysFinish(bricolsoftconsulting.com/2011/12/23/…)做一些生命周期测试,您会看到当另一个活动始终处于启用状态且始终完成启用时,此代码会导致错误(IllegalStateException:无法执行此操作在onSaveInstanceState之后)。在try / catch中包装上面的代码不是最优雅的解决方案,但它似乎可以使所有工作正常。
Theo 2012年

这几乎起作用了。后来我在绘图UI上得到了Stackoverflow。
绝对

14

我正在开发一个应用程序,该应用程序的布局与启动片段的“动作栏”中的选项卡相似,其中一些片段中有多个嵌入式片段。

当我尝试运行该应用程序时,出现了相同的错误。似乎如果取消选择选项卡后实例化xml布局中的Fragments,然后重新选择它,我会得到充气机错误。

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

我希望这能够帮到你。


谁能评论这种方法的有效性?我发现不幸的是,只能在一个级别上深度使用Fragments-可能根本不使用它们。以编程方式将其添加到占位符视图组将无须警告吗?
拉斐尔·诺布雷

似乎仍然为我工作,我也可以将它们换进和换出视点。一个警告,我只是在蜂窝上这样做,与冰淇淋三明治不兼容。
draksia 2012年

4

我也遇到过同样的问题,经过了几天的努力,应该说,克服这个问题的最简单方法是在选择/取消选择制表符时使用fragment.hide()/fragment.show()。 ()。

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

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

这种方法还有一个额外的优势-使用hide()/ show()不会导致片段视图失去其状态,因此,例如,无需还原ScrollViews的先前滚动位置。

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

我想听听更有经验的开发人员的评论。


0

如果您发现嵌套片段未被删除或复制(例如,在“活动重新启动”,“屏幕旋转”时),请尝试更改:

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();

在这里学习

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.