无法使用Fragment.setRetainInstance()作为Activity.onRetainNonConfigurationInstance()的替代品

Ste*_*ven 13 android android-fragments

根据Android API文档,不推荐使用Activity.onRetainNonConfigurationInstance()来支持Fragment.setRetainInstance().

但是,我遇到了两个不同的情况,Fragment.setRetainInstance()似乎不可行.

  1. 如果Fragment包含WebView.根据Diane Hackborne的说法,您不能在配置更改中重用WebView.我想这意味着你需要在屏幕旋转时允许Fragment拆除并重新创建WebView,并使用WebView.saveState()WebView.restoreState()来恢复Web视图状态.

  2. 如果Fragment属于配置更改后不再存在的布局,则当FragmentManager尝试恢复Fragment时,它将抛出:

    java.lang.IllegalArgumentException: No view found for id 0x7f060091 for fragment
    
    Run Code Online (Sandbox Code Playgroud)

    如果您在横向模式下具有双片段布局,但在纵向模式下具有单片段布局,则会发生这种情况(例如).当从landscape转换为portrait时,如果setRetainInstance()设置为true,则Fragment都不会被销毁,但是一个片段不再具有要重新附加的有效视图,因此是异常.

因此,如果您正在构建基于Fragment的应用程序,并且需要在配置更改之间保留数据(例如对运行的AsyncTasks的引用),并且您不能使用Fragment.setRetainInstance(),并且没有Fragment.onRetainNonConfigurationInstance (),最好的方法是什么?

ant*_*nyt 8

即使您使用Fragment.setRetainInstance(),Fragment仍会拆除其视图并在配置更改后重新创建它.也就是说,onDestroyView()并且onCreateView()将在该序列被调用.确保使对WebView的旧引用无效onDestroyView().您不必担心重新使用WebView - 将使用正确的Activity上下文重新创建新的WebView .这有点无关紧要,因为保存的WebView状态下,你仍然需要调用WebView.saveState(Bundle)Fragment.onSaveInstanceState(Bundle),并WebView.restoreState(Bundle)Fragment.onViewCreated(Bundle).这只意味着Fragment.setRetainInstance()仍然与WebViews的使用兼容.

您提供的关于视图容器不再存在于另一个方向的示例意味着您不需要保留任何数据 - 在屏幕旋转后根本不会使用该片段.

在任何情况下,不是使单个Fragment处理UI和AsyncTask加载,而是可以将它们分成两个片段 - 具有AsyncTask的片段根本不需要连接到视图层次结构,并且可以设置为保留实例.这简化了您的顾虑,并使建筑更清洁.当AsyncTask完成时,您需要回调UI片段以传递结果(例如findFragmentById/Tag,setTargetFragment,自定义侦听器......).管理AsyncTask的片段需要能够在旋转后检索对UI片段的新实例的引用.


Ste*_*ven 0

看起来我的问题没有答案,但这就是我最终所做的:

  1. 对于包含需要恢复的WebView 的Fragment ,请重写Fragment.onSaveInstanceState(Bundle state)并调用WebView.saveState(bundle)。然后在Fragment.onViewCreated(View view, Bundle savingInstanceState)中,如果savingInstanceState不为 null,则调用webView.restoreState(savedInstanceState) 。

  2. 对于包含需要保留的实时AsyncTasks 的Fragment ,请重写Fragment.onDestroy()并将这些任务保存在我的 Application 对象中。(或者,也建议将它们存储在静态变量中)。然后在Fragment.onCreate(Bundle savingInstanceState)中,检查这些任务是否不为空,如果是,则恢复它们。(这意味着依赖于应用程序,但在我的例子中,当AsyncTask完成时,我恢复要在Fragment上调用的回调)。

我不确定这是否是最好的解决方案,但它似乎解决了我遇到的问题。

尽管如此,我发现整个情况相当混乱(区分onSaveInstanceState()onRetainNonConfigurationInstance()onDestroy(),并决定在每种情况下需要保存什么)。