当使用FragmentTransaction.replace()时,Android Fragment视图状态丢失



我有一个相当大的问题,我不太明白发生了什么。我正在开发一个使用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();

这成功地替换了我的片段。我的问题如下。在一个片段中,我有一个从用户输入构建的项目列表。现在,当用户单击next,然后单击back按钮(返回到列表)时,列表为空,因为视图被销毁了。现在,我注意到以下内容:

    没有调用
  1. onSaveInstanceState。我相信这是因为只有当父Activity告诉它时才会调用它。基于文档:"有很多情况下,一个片段可能大部分被拆除(如当放置在后台堆栈没有UI显示),但它的状态不会被保存,直到它拥有的活动实际上需要保存它的状态。"显然,在FragmentTransaction上执行替换并不属于这种情况。有人能证实这一点吗或者有更好的解释吗?
  2. setOnRetainInstanceState(true)在这种情况下没有帮助。再一次,我相信这与来自文档的信息有关:"控制是否在活动重新创建中保留片段实例(例如从配置更改)"。我不执行任何动作在重新创建活动,所以这是没有用的。

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

如果不能看到您的片段的代码,这是一个猜测,但在过去,我遇到了同样的问题,我发现在onViewStateRestored中重置ListFragment中的适配器似乎可以做到这一点。

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

考虑到文档中声明该方法在onActivityCreated之后但在onStart之前调用,这很奇怪。但似乎它也在其他时候被调用,因为当最近的片段事务弹出后堆栈这个方法被调用之前,以前取代的片段被显示。拥有片段的活动没有以任何方式暂停或模糊,所以根据文档onViewStateRestored不应该被调用,因为只是片段被修改了。

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

假设这都是真的,那么当用户点击回Android将调用onCreateView。任何状态,你已经存储在片段的实例变量应该仍然在那里,所有你需要做的是重新填充视图…也许可以在ListView或其他地方设置适配器。

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

最新更新