10

我有一个很大的问题,我不完全理解发生了什么。我正在开发一个使用Fragments(来自支持库)的应用程序,并且正在使用FragmentTransaction.replace()将新碎片放在后端堆栈上并替换旧碎片。代码如下:Android片段查看状态使用FragmentTransaction.replace时丢失()

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未被调用。我相信这是因为只有在父活动告诉它时才会调用它。基于文档:“在很多情况下,碎片可能大部分被拆除(例如,当放置在背堆栈上而没有UI显示时),但是其状态不会被保存,直到其拥有的活动实际上需要保存其状态“。显然,在FragmentTransaction上执行替换并不是那些时间之一。有没有人有这方面的确认或更好的解释?
  2. setOnRetainInstanceState(true)在这种情况下没有帮助。再次,我认为这与来自文档的信息有关:“控制是否在重新创建Activity(例如从配置更改)中保留片段实例”。我在重新创建活动时没有执行任何操作,所以这没用。

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

回答

2

不能看到你的片段的代码这是一个猜测,但在过去我遇到了同样的问题,我发现重置在适配器似乎做的伎俩。

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

这是奇怪的考虑文档指出这种方法onActivityCreated之后,但onStart之前调用。但似乎它在其他时候也被调用,因为当最近的片段事务从背堆栈弹出时,在显示先前替换的片断之前调用此方法。拥有这些片段的活动并未以任何方式暂停或遮盖,因此根据文档onViewStateRestored不应调用,因为片段已被修改。但是,无论如何,这似乎工作。

2

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

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

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