10

我遇到了一个很大的问题,我不太明白发生了什么。我正在开发一个使用 Fragments(来自支持库)的应用程序,并且正在使用FragmentTransaction.replace()将新的 Fragments 放置到后台堆栈并替换旧的。代码如下所示:

FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = ft.beginTransaction();
// Animations in my res/anim folder
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.fragment_container, newFragment, tag);
ft.addToBackStack(null);
ft.commit();

这成功替换了我的片段。我的问题如下。在一个片段中,我有一个根据用户输入构建的项目列表。现在,当用户单击下一步然后单击后退按钮(返回列表)时,列表为空,因为视图已被破坏。现在,我注意到以下几点:

  1. onSaveInstanceState 没有被调用。我相信这是因为只有在父 Activity 告诉它时才会调用它。根据文档:“在许多情况下,片段可能大部分被拆除(例如,当放置在没有显示 UI 的后台堆栈时),但在其拥有的活动实际需要保存其状态之前,它的状态不会被保存."。显然,对 FragmentTransaction 执行替换并不是其中之一。有人对此有确认或更好的解释吗?
  2. setOnRetainInstanceState(true) 在这种情况下没有帮助。同样,我相信这与文档中的信息有关:“控制是否在 Activity 重新创建期间保留片段实例(例如从配置更改中)”。我没有在重新创建活动时执行任何操作,所以这没有用。

所以,我想我的主要问题是:有没有办法在使用时保留视图状态(只保留片段)replace?有FragmentTransaction.add(),但也有一些问题。一种是没有执行退出动画,因此动画不正确。另一个是旧片段(被置于不可见状态的片段)仍然可以点击的新片段。例如,如果我有一个 ListFragment,并且我通过使用 add 在其上放置一个内容片段,我仍然可以单击 ListFragment 中的列表项。

4

2 回答 2

2

听起来您只需要确保已正确实现 onCreateView 和 onDestroyView。您所描述的情况似乎表明,当列表片段被放在后台堆栈(作为替换事务的结果)时,Android 正在调用 onDestroyView 以释放一些资源。但是,它显然没有破坏列表片段,因为当您点击返回时,您将返回片段的相同实例。

假设这一切都是真的,那么当用户点击返回时,Android 将调用 onCreateView。您存储在片段的实例变量中的任何状态都应该仍然存在,您需要做的就是重新填充视图......也许在 ListView 或其他上设置适配器。

还要确保您的 onSaveInstanceState() 回调确实保存了重建视图所需的任何实例状态。这样,如果片段确实被完全销毁,FragmentManager 可以在稍后需要重新创建片段时恢复状态。

于 2013-04-13T06:58:59.330 回答
2

无法看到您的片段代码,这有点猜测,但在过去我遇到过同样的问题,我发现在您的ListFragmentin中重置适配器onViewStateRestored似乎可以解决问题。

public void onViewStateRestored (Bundle savedInstanceState)
{
    super.onViewStateRestored (savedInstanceState);
    setListAdapter(new ArrayAdapter(Activity, R.layout.nav_item, objects));
}

考虑到文档指出此方法在 afteronActivityCreated但 before调用,这很奇怪onStart。但它似乎在其他时间也被调用,因为当最近的片段事务从返回堆栈中弹出时,此方法在显示先前替换的片段之前被调用。拥有片段的活动没有以任何方式暂停或隐藏,因此根据文档onViewStateRestored不应调用,因为只是修改了片段。但这似乎仍然有效。

于 2013-04-13T05:52:02.617 回答