Android碎片问题

4

我正在使用Fragments来表示应用程序中的不同视图。在浏览视图之间导航时,我使用以下代码替换Fragments:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right);
ft.replace(R.id.main_linearlayout_fragmentcont, frag);
ft.addToBackStack(null);
ft.commit();

我在旋转屏幕并重建活动时遇到了很多问题。我需要支持旧版本的Android,因此android:configChanges="orientation"不是一个选项。很多问题都是由于Android保存Fragment状态的性质造成的。
以下是我遇到的问题:
1)当自动恢复后弹出事件时,片段转换不会记住我的自定义动画。但是它们记得我的BackStack。我知道我可以编写自己的后退处理程序,使用动画进行替换并完全摆脱pop,但我想知道是否有一种方法可以在调用popBackStack()之前重置动画或让FragmentManager在自动旋转后记住动画。
2)我还有另一个问题,我在一个顶级片段视图中有一堆子视图(线性布局),它们包含自己的片段。这些子视图是以编程方式创建和填充的。在旋转后重新创建我的片段时,在Fragment对象的onCreateView中以编程方式重建子视图,然后在每个子视图下面得到重复的片段(1-我以编程方式创建,1- Android Fragments从恢复中创建)。我假设这是因为我在旋转后以相同的id以编程方式重建了子视图。有没有办法防止Fragments被恢复?Android何时将Fragments从savedState注入到这些我以编程方式构建的视图中?我该如何防止这种情况发生?
3)上面的替换代码似乎会多次触发我的片段对象的onCreateView。这是没有旋转时发生的,只有在我仅运行上述代码一次时才会发生。片段的onCreateView被调用多次的原因是什么?
关于片段的问题: 1)我能否防止Android在重建活动时自动恢复片段?我该如何做到这一点?它是基于LinearLayout的ID吗?我可以在onStop时调用LinearLayout的removeAllViews吗?这样保存时就不存在该视图了吗?
2)是否有一种方法可以将片段添加到我引用但没有ID的LinearLayout中?似乎Fragment add、replace API需要一个int ID。
谢谢!

这个 bug 存在于 Android 平台和支持库 18 中。问题 25994 碎片动画未能在配置更改时保存。解决方法需要对支持库进行补丁修复。如果这是你的应用程序的一个必要特性,你可以要么打补丁修复库,要么选择避免子碎片而采用更深层次的 activity 耦合。 - James Wald
2个回答

3

1) 如果你知道怎么做,请告诉我,我也很生气。

2) 你可能在顶层Fragment中调用了add方法来执行FragmentTransaction,但是还原操作也会添加Fragment,导致重复!选项1:使用replace代替。选项2:(首选)检查if(savedInstances==null) { // do transaction } else { //let the system rebuilt it itself}

3) 如果你正在更改作为Fragment一部分的视图的布局(通过调用添加或替换方法),则FragmentManager会再次创建该视图。我仍然不确定这是一个错误还是一个特性,如果它是一个特性,那为什么会这样。如果你发现了,请告诉我。

4) 不要随意修改布局,如果你想删除它们,请使用while(popBackStackImmediately){},但是如果深入理解系统在做什么,并且通常没有理由不让它自动完成。

5) 如果你有引用,你就有ID:View.getId()

愉快的编码!


  1. 我以为我疯了,因为我认为这一定是可能的,但我却无法弄清楚。
  2. 我会尝试替换,但我认为恢复的片段是在我编程创建之后添加的。在这种情况下,我无法访问savedInstances,并且它会在未来的按钮单击事件中发生。我希望不必保存savedInstances并将其传递到此代码中。我想尝试为每个新构建的视图生成一个唯一的ID。我希望这样可以解决问题。
  3. 感谢您提供的详细信息。
- Derek Gebhard
  1. 我同意。使用Fragments时,似乎无法像我想要的那样掌控一切,这让人感到沮丧。
  2. 我不想给视图分配一个ID,但我认为在Fragments中我做不到这一点。
- Derek Gebhard
  1. 如果您想阻止系统重新创建,我认为最好的选择是在每个片段上包含一个标签,并使用 if(savedInstances!=null) findFragmentByTag->remove,这也适用于第4项。5) 据我所知,如果您不为视图分配ID,则系统会在运行时自动生成一个ID,并且您可以通过 myLinearLayout.getId(); 访问它。对于最后一点,我可能是错误的,您需要自己测试一下。
- Budius

0
如果您更改设备的方向,则需要在活动中检查验证,并使用堆栈管理片段,以确保流程不会受到影响。
if(savedInstanceState == null) {

   mFragmentManager = getSupportFragmentManager();
   FragmentTransaction fragmentTransaction = 

   mFragmentManager.beginTransaction();

   FragmentOne fragment = new FragmentOne();

   fragmentTransaction.add(R.id.fragment_container, fragment);
   fragmentTransaction.commit();
}

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