为什么在onSaveInstanceState()中保存非Parcelable对象的Hashtable有时会起作用?

时间:2011-03-03 21:02:24

标签: android android-activity bundle parcelable activity-lifecycle

在阅读了介绍性的Android编程书之后,我想改变示例应用程序,以巩固我对一些未真正涵盖的主题的理解。在进行更改时,我犯了一个错误,但我很好奇为什么错误在某些情况下有效但在其他情况下却没有。

应用程序中的活动在Hashtable<Integer, Question>中存储一系列问题,其中Question是一个包含int和两个字符串的小类。最初编写时,活动会在每onCreate()个{@ 1}}上从服务器下载问题,因此我希望实施onSaveInstanceState()以防止一些冗余下载。 onSaveInstanceState()使用putSerializable()将Hashtable保存到Bundle中。

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
            // mQuestions is a member variable of 
            // type Hashtable<Integer, Question>
    if (mQuestions != null && mQuestions.size() > 0) {
        outState.putSerializable(SAVED_QUESTIONS, mQuestions);
    }
}

在我知道Parcelable是什么或如何实现之前,它完全适用于屏幕方向的变化。我只知道当我按下模拟器的主页键和应用程序静默时出现问题,无法在没有LogCat输出的情况下崩溃。堆栈跟踪让我查找Parcelable并使Question实现它。

我的问题不是我做错了什么。问题是:当问题类没有实现Parcelable时,为什么应用程序只在按Home而不是屏幕方向更改时崩溃?

3 个答案:

答案 0 :(得分:2)

据我所知,Android在配置更改后重新创建活动时不会序列化实例状态。这就是你的代码有效的原因。持久对象不需要是可分解的,因为它们只存在于内存中。

这看起来像是一种优化。 Android知道在这种情况下不会终止进程,也不需要将实例状态保存到文件中。 (理论上,这个过程可以在配置更改期间终止,我真的不知道Android如何解决这个问题。)

但是当用户按下Home键时,您的应用程序将变为背景。并且在内存不足的情况下可以终止其进程。 Android需要将活动的状态保存到文件中,以便将来能够恢复您的应用及其活动。在这种情况下,实例状态实际上是序列化的并保存到持久存储中。这就是你的代码不起作用的原因。

进程终止可以随时发生,因此您不能依赖某些实现细节。只需将实例状态设为可分区或可序列化,您就不会再遇到此问题了。

答案 1 :(得分:1)

  

引用史蒂夫·莫斯利

根据http://developer.android.com/reference/android/app/Activity.html中有关活动状态的文档,请注意 安全使用onSaveInstanceStateonRestoreInstanceState

该文件陈述(在“活动生命周期”部分):

  

请注意保存很重要   相反,onPause()中的持久数据   onSaveInstanceState(Bundle)的   因为后者不属于   生命周期回调,所以不会   在所描述的每种情况下都会被呼   在其文档中。

换句话说,请将保存/恢复代码改为onPause()onResume()

答案 2 :(得分:0)

应用程序没有崩溃。当用户单击Home键时,它就会被关闭。这就是LogCat没有输出的原因。

在Activity.onDestroy()中设置断点以确认这一点。如果我正确onDestroy()将被调用但onSaveInstanceState()不会被调用,因为onSaveInstanceState()仅在应用程序处于后台状态时被调用,而不是在它被关闭时被调用。

如果您需要在关机时保存应用程序状态,请将代码放在onDestroy()中并将其保存为比Bundle更持久的内容。

百里