在内存不足的情况下保存实例状态
saving instance state on memory low situations
我有一个由 DialogFragment
class 环绕的警告对话框。该对话框具有自定义布局,我在其中显示项目列表(我使用 ListView
和适当的适配器)。项目列表非常庞大且重要,所以我将其保存在 DialogFragment
的 onPause()
中的 Fragment
class 中,就像在 this example 中一样。
一切正常,除了一种非常罕见的情况:当我离开应用程序时对话框 window 打开(通过按 "home" 按钮)并且设备内存不足,它会杀死我的应用程序的过程。当我稍后回到我的应用程序时,它会尝试重新创建对话框,但会崩溃(我在对话框的 ListView
适配器中得到一个 NullPointerException
),因为它无法恢复显示在我左边打开的对话框。发生这种情况是因为当系统终止我的应用程序进程时,我存储对话框状态的 Fragment
也被破坏,因此我的 DialogFragment
无法重新创建其对话框,因为它没有列表适配器的数据源。
我想从你那里得到的是为我提供一种更好的方法来保存我的对话框状态 window 以便即使在我的应用程序进程被终止后也可以重新创建它,或者告诉我一种取消对话框的方法如果项目列表在恢复之前是 null
对话框(我的意思是在重新创建过程中的某个地方取消对话框)。我不认为数据库是存储该数据的好方法,因为它会花费太长时间。如果没有关于其适配器的信息,我更喜欢一种停止对话框重新创建的方法。
更新:
实施 Parcelable
在应用程序的生命周期中保存您的对象确实是一个绝妙的主意。将对象写入 Parcel
很快(相信我,除非您开始不恰当地使用它,否则您不会看到生命周期更改之间的任何延迟),并且保存和恢复应用程序实例状态的过程由 ActivityManager
进程,所以即使不仅 Activity
,而且托管整个应用程序的进程都被 Android 系统破坏,ActivityManager
会维护 Parcel
你的对象所在的位置如果 Activity
在新进程中从头开始重新创建,则保存并恢复其状态。非常感谢@Naveed 鼓励我尝试这种做法!
对于那些仍然不明白节省实例状态真正意义的人的注意事项:
在其生命周期事件中保存 Activity
的实例状态意味着维护仅对您的应用程序的当前 UI 或用户的当前进度有意义但对您的应用程序不是必需的信息更改或用户明确停止应用程序(通过按后退按钮)并稍后再次启动它。这种特殊形式的信息实际上是临时的,应该保存在 Bundle
对象的 onSaveInstanceState()
回调方法中,方法是使用原始 Java 类型的 put...()
方法或实现 Parcelable
接口在您的自定义 classes 中,后来在 onCreate()
或 onRestoreInstanceState()
callbakcs 中恢复。
所有其他对用户重要的数据,无论他们是明确关闭您的应用程序还是暂时保留它,都应保存在持久存储中,例如 SQLite
数据库或SharedPreferences
系统,因此只要用户或您的应用程序再次需要以前的进度,它就可以恢复。
你应该在 onPause()
回调方法中保存这种形式的数据,因为它是保证在系统能够销毁你的应用进程之前调用的最后一个方法,以防它需要恢复一些资源。如果您选择在 onPause()
之后调用的方法中保存数据,即 onStop()
或 onDestroy()
,您将面临无法保存数据的巨大风险,因为这些方法可能永远不会如果系统决定在某些非常糟糕(但不一定罕见)的情况下立即终止您的应用程序,则会被调用。
另一件事:请仅在存储少量数据时使用 SharedPreferences
,因为它不是为存储列表、集合或包而构建的。考虑多花几个小时为您的应用程序实现一个 SQLite
数据库接口,并更轻松地使用它来维护大量信息。
系统会在由于内存问题即将终止您的应用程序时调用onSaveInstanceState
。您可以在 onSaveInstanceState 中保存任何与状态相关的信息。如果您的数据是原始类型、Parcelable 或 Serializable,它可以保存在一个包中。
重新创建 Activity 后,您可以在 onRestoreInstanceState
或 onCreate
或 fragment life cycle 中的以下任何位置恢复它。
onCreate(Bundle) called to do initial creation of the fragment.
onCreateView(LayoutInflater, ViewGroup, Bundle) creates and returns the view hierarchy associated with the fragment.
onActivityCreated(Bundle) tells the fragment that its activity has completed its own Activity.onCreate().
onViewStateRestored(Bundle)tells the fragment that all of the saved state of its view hierarchy has been restored.
如果您只是不想显示对话框。然后,您可以在 onResume
中进行空检查,如果数据为空则不创建适配器,如果对话框可见则关闭该对话框。
更新:可打包示例:
public class MyObject implements Parcelable {
private String myString;
private int myInt;
protected MyObject(Parcel in) {
myString = in.readString();
myInt = in.readInt();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(myString);
dest.writeInt(myInt);
}
@SuppressWarnings("unused")
public static final Parcelable.Creator<MyObject> CREATOR = new Parcelable.Creator<MyObject>() {
@Override
public MyObject createFromParcel(Parcel in) {
return new MyObject(in);
}
@Override
public MyObject[] newArray(int size) {
return new MyObject[size];
}
};
}
我有一个由 DialogFragment
class 环绕的警告对话框。该对话框具有自定义布局,我在其中显示项目列表(我使用 ListView
和适当的适配器)。项目列表非常庞大且重要,所以我将其保存在 DialogFragment
的 onPause()
中的 Fragment
class 中,就像在 this example 中一样。
一切正常,除了一种非常罕见的情况:当我离开应用程序时对话框 window 打开(通过按 "home" 按钮)并且设备内存不足,它会杀死我的应用程序的过程。当我稍后回到我的应用程序时,它会尝试重新创建对话框,但会崩溃(我在对话框的 ListView
适配器中得到一个 NullPointerException
),因为它无法恢复显示在我左边打开的对话框。发生这种情况是因为当系统终止我的应用程序进程时,我存储对话框状态的 Fragment
也被破坏,因此我的 DialogFragment
无法重新创建其对话框,因为它没有列表适配器的数据源。
我想从你那里得到的是为我提供一种更好的方法来保存我的对话框状态 window 以便即使在我的应用程序进程被终止后也可以重新创建它,或者告诉我一种取消对话框的方法如果项目列表在恢复之前是 null
对话框(我的意思是在重新创建过程中的某个地方取消对话框)。我不认为数据库是存储该数据的好方法,因为它会花费太长时间。如果没有关于其适配器的信息,我更喜欢一种停止对话框重新创建的方法。
更新:
实施 Parcelable
在应用程序的生命周期中保存您的对象确实是一个绝妙的主意。将对象写入 Parcel
很快(相信我,除非您开始不恰当地使用它,否则您不会看到生命周期更改之间的任何延迟),并且保存和恢复应用程序实例状态的过程由 ActivityManager
进程,所以即使不仅 Activity
,而且托管整个应用程序的进程都被 Android 系统破坏,ActivityManager
会维护 Parcel
你的对象所在的位置如果 Activity
在新进程中从头开始重新创建,则保存并恢复其状态。非常感谢@Naveed 鼓励我尝试这种做法!
对于那些仍然不明白节省实例状态真正意义的人的注意事项:
在其生命周期事件中保存 Activity
的实例状态意味着维护仅对您的应用程序的当前 UI 或用户的当前进度有意义但对您的应用程序不是必需的信息更改或用户明确停止应用程序(通过按后退按钮)并稍后再次启动它。这种特殊形式的信息实际上是临时的,应该保存在 Bundle
对象的 onSaveInstanceState()
回调方法中,方法是使用原始 Java 类型的 put...()
方法或实现 Parcelable
接口在您的自定义 classes 中,后来在 onCreate()
或 onRestoreInstanceState()
callbakcs 中恢复。
所有其他对用户重要的数据,无论他们是明确关闭您的应用程序还是暂时保留它,都应保存在持久存储中,例如 SQLite
数据库或SharedPreferences
系统,因此只要用户或您的应用程序再次需要以前的进度,它就可以恢复。
你应该在 onPause()
回调方法中保存这种形式的数据,因为它是保证在系统能够销毁你的应用进程之前调用的最后一个方法,以防它需要恢复一些资源。如果您选择在 onPause()
之后调用的方法中保存数据,即 onStop()
或 onDestroy()
,您将面临无法保存数据的巨大风险,因为这些方法可能永远不会如果系统决定在某些非常糟糕(但不一定罕见)的情况下立即终止您的应用程序,则会被调用。
另一件事:请仅在存储少量数据时使用 SharedPreferences
,因为它不是为存储列表、集合或包而构建的。考虑多花几个小时为您的应用程序实现一个 SQLite
数据库接口,并更轻松地使用它来维护大量信息。
系统会在由于内存问题即将终止您的应用程序时调用onSaveInstanceState
。您可以在 onSaveInstanceState 中保存任何与状态相关的信息。如果您的数据是原始类型、Parcelable 或 Serializable,它可以保存在一个包中。
重新创建 Activity 后,您可以在 onRestoreInstanceState
或 onCreate
或 fragment life cycle 中的以下任何位置恢复它。
onCreate(Bundle) called to do initial creation of the fragment.
onCreateView(LayoutInflater, ViewGroup, Bundle) creates and returns the view hierarchy associated with the fragment.
onActivityCreated(Bundle) tells the fragment that its activity has completed its own Activity.onCreate().
onViewStateRestored(Bundle)tells the fragment that all of the saved state of its view hierarchy has been restored.
如果您只是不想显示对话框。然后,您可以在 onResume
中进行空检查,如果数据为空则不创建适配器,如果对话框可见则关闭该对话框。
更新:可打包示例:
public class MyObject implements Parcelable {
private String myString;
private int myInt;
protected MyObject(Parcel in) {
myString = in.readString();
myInt = in.readInt();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(myString);
dest.writeInt(myInt);
}
@SuppressWarnings("unused")
public static final Parcelable.Creator<MyObject> CREATOR = new Parcelable.Creator<MyObject>() {
@Override
public MyObject createFromParcel(Parcel in) {
return new MyObject(in);
}
@Override
public MyObject[] newArray(int size) {
return new MyObject[size];
}
};
}