FragmentActivity onSaveInstanceState 没有被调用
Posted
技术标签:
【中文标题】FragmentActivity onSaveInstanceState 没有被调用【英文标题】:FragmentActivity onSaveInstanceState not getting called 【发布时间】:2013-04-02 20:29:10 【问题描述】:我已经看到了一些关于onSaveInstanceState
没有被Fragment
s 调用的类似问题,但在我的情况下Fragment
s 工作正常,主要的FragmentActivity
有问题。
相关代码看起来相当简单:
public class MyFActivity extends FragmentActivity implements ActionBar.TabListener
String[] allValues; // data to save
@Override
protected void onSaveInstanceState (Bundle outState)
Log.d("putting it!", allValues.toString());
outState.putStringArray("allValues", allValues);
super.onSaveInstanceState(outState);
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
if (savedInstanceState != null)
allValues = savedInstanceState.getStringArray("allValues");
Log.d("getting it!", allValues.toString());
暂停活动时(使用后退按钮),永远不会调用 onSaveInstanceState
,因此,在恢复应用程序时,savedInstanceState
始终是 onCreate
方法中的 null
。我尝试添加这样的块:
@Override
public void onPause()
super.onPause();
onSaveInstanceState(new Bundle());
这是在https://***.com/a/14195202/362657 中建议的,但是当onSaveInstanceState
然后被调用时,savedInstanceState
在onCreate
方法中仍然是null
。我错过了什么?
【问题讨论】:
“暂停活动时(使用后退按钮)”通常会破坏片段,因此savedInstanceState
会丢失。当您旋转设备时,您是否在onCreate()
中看到了相应的saveInstanceState
?
而不是 onCreate,也许您应该使用 onResume()?如果活动只是暂停,那么 onCreate() 不应该被再次调用,onResume() 应该
嗯,这就解释了!毁了它。
【参考方案1】:
这里的问题是您误解了onSaveInstanceState
的工作原理。它旨在保存Activity
/Fragment
的状态,以防操作系统因内存原因或配置更改而需要销毁它。然后当Activity
/Fragment
返回/重新启动时,此状态会在onCreate
中传回。
在Fragment
中,它们的所有生命周期回调都直接绑定到它们的父Activity
。因此,当 Fragment
的父级 Activity
调用了 onSaveInstanceState
时,onSaveInstanceState
会在 Fragment
上被调用。
暂停活动时(使用后退按钮),永远不会调用 onSaveInstanceState,因此,在恢复应用程序时,onCreate 方法中的 savedInstanceState 始终为 null。
当按下返回时,用户正在销毁Activity
,因此它的子Fragment
s,因此没有理由调用onSaveInstanceState
,因为实例正在被销毁。当你重新打开Activity
时,它是一个全新的实例,没有保存状态,所以onCreate
传入的Bundle
是null
。这完全符合设计。但是,尝试旋转设备或点击主页按钮,然后您会看到Activity
及其子Fragment
s 调用了onSaveInstanceState
,并在返回时传入onCreate
。
您添加的hack,直接在onPause
内部调用onSaveInstanceState(new Bundle());
,是一种非常糟糕的做法,因为您应该永远不要直接调用生命周期回调。这样做会使您的应用程序进入非法状态。
如果您真正想要的是将数据保留在应用实例之外,我建议您考虑使用SharedPreferences
或databases 获取更高级的数据。然后,您可以将持久性数据保存在 onPause()
中或随时更改。
希望这会有所帮助。
【讨论】:
感谢您的详尽解释。我的错误印象是后退按钮将活动置于后台,而不是破坏它。 不客气,这是一个棘手的概念,并且没有像我希望看到的那样记录在案。 @dymmeh 太棒了,+1 先生 很好的解释。我不确定为什么我的片段中没有调用 onSaveInstanceState。现在我明白了。谢谢In a Fragment, all of their lifecycle callbacks are directly tied to their parent Activity. So onSaveInstanceState gets called on the Fragment when its parent Activity has onSaveInstanceState called.
那么由单个活动托管的片段呢?从理论上讲,它们像 onSavedInstanceState
和 ... 这样的方法永远不会被调用,因为它们在同一个活动中传输,对吧?【参考方案2】:
在已接受答案的更新中:
如果您将ViewPager
与FragmentStatePagerAdapter
(而不是FragmentPagerAdapter
)一起使用,则可能会调用片段的onSaveInstanceState
FragmentStatePagerAdapter
当有大量页面时,此版本的寻呼机更有用,更像列表视图。当页面对用户不可见时,它们的整个片段可能会被销毁,只保留该片段的已保存状态。与 FragmentPagerAdapter 相比,这允许分页器保留与每个访问的页面相关联的内存更少,但代价是在页面之间切换时可能会增加更多开销。
别忘了:
使用 FragmentPagerAdapter 时,宿主 ViewPager 必须设置有效的 ID。
【讨论】:
【参考方案3】:不是对问题的准确答案,但可能对某人有所帮助。 就我而言,我打电话给
@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState)
super.onSaveInstanceState(outState, outPersistentState);
我将上面的代码替换为如下,一切正常
@Override
protected void onSaveInstanceState(@NonNull Bundle outState)
super.onSaveInstanceState(outState);
【讨论】:
以上是关于FragmentActivity onSaveInstanceState 没有被调用的主要内容,如果未能解决你的问题,请参考以下文章
Activity 和 FragmentActivity 的区别
Android - 活动与 FragmentActivity? [复制]
Fragment 和 FragmentActivity 有啥区别?
Activity、AppCompatActivity、FragmentActivity 和 ActionBarActivity:啥时候使用?