java 以实例状态保存自定义对象数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3223029/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Save custom object array in instance state
提问by Felix
I have a List<CustomObject>(where CustomObjectcomes from an external library -- I can't make changes to it). I want to save this in onSaveInstanceState(Bundle), but I can't seem to do it. Here are the options that I've tried:
我有一个List<CustomObject>(CustomObject来自外部库的地方——我无法对其进行更改)。我想将其保存在 中onSaveInstanceState(Bundle),但我似乎无法做到。以下是我尝试过的选项:
outState.putSerializable(KEY, (ArrayList<CustomObject>) myList); // because myList is instantiated as an ArrayList
outState.putSerializable(KEY, myList.toArray());
Both options workwhen switching orientation on the phone (yes, onSaveInstanceStateis called when switching orientation -- I checked in logcat). However, when the current activity tries to start another one (with startActivity(Intent)), Android pauses the current activity and calls onSaveInstanceState()again. This time, it fails, for some reason unknown to me. The fishy thing is that onSaveInstanceState()executes successfully. The stack trace printed doesn't point to any of my code:
在手机上切换方向时,这两个选项都有效(是的,onSaveInstanceState在切换方向时调用——我检查了 logcat)。但是,当当前活动尝试启动另一个活动(使用startActivity(Intent))时,Android 会暂停当前活动并onSaveInstanceState()再次调用。这一次,它失败了,出于某种我不知道的原因。可疑的是onSaveInstanceState()执行成功。打印的堆栈跟踪没有指向我的任何代码:
E/AndroidRuntime(23898): java.lang.RuntimeException: Parcel: unable to marshal value my.custom.Object@5e07e43b
E/AndroidRuntime(23898): at android.os.Parcel.writeValue(Parcel.java:1087)
E/AndroidRuntime(23898): at android.os.Parcel.writeArray(Parcel.java:519)
E/AndroidRuntime(23898): at android.os.Parcel.writeValue(Parcel.java:1072)
E/AndroidRuntime(23898): at android.os.Parcel.writeMapInternal(Parcel.java:469)
E/AndroidRuntime(23898): at android.os.Bundle.writeToParcel(Bundle.java:1445)
E/AndroidRuntime(23898): at android.os.Parcel.writeBundle(Parcel.java:483)
E/AndroidRuntime(23898): at android.app.ActivityManagerProxy.activityPaused(ActivityManagerNative.java:1427)
E/AndroidRuntime(23898): at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3106)
E/AndroidRuntime(23898): at android.app.ActivityThread.access00(ActivityThread.java:119)
E/AndroidRuntime(23898): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1870)
E/AndroidRuntime(23898): at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(23898): at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime(23898): at android.app.ActivityThread.main(ActivityThread.java:4363)
E/AndroidRuntime(23898): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(23898): at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime(23898): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
E/AndroidRuntime(23898): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
E/AndroidRuntime(23898): at dalvik.system.NativeStart.main(Native Method)
Is there any way to store custom objects in the instance state?
有没有办法在实例状态中存储自定义对象?
采纳答案by Macarse
Make your CustomObjectimplement Parcelableand use:
制作您的CustomObject工具Parcelable并使用:
outState.putParcelable(KEY, myList);
onSaveInstanceState(outState);
Also check thistutorial.
另请查看本教程。
EDITafter CommonsWare comment:
在 CommonsWare 评论后编辑:
If your CustomObjectdoesn't implement Serializableor ParcelableI would try wrapping it inside an object of your own and add:
如果您CustomObject没有实现,Serializable或者Parcelable我会尝试将其包装在您自己的对象中并添加:
private void readObject(ObjectInputStream aStream) throws IOException, ClassNotFoundException { /*Your deserialization */ }private void writeObject(ObjectOutputStream aStream) throws IOException { /*Your serialization */}
private void readObject(ObjectInputStream aStream) throws IOException, ClassNotFoundException { /*Your deserialization */ }private void writeObject(ObjectOutputStream aStream) throws IOException { /*Your serialization */}
回答by CommonsWare
Have your List<CustomObject>be held by a service and make it accessible to your activities via the local binding pattern.
让您List<CustomObject>由服务持有,并通过本地绑定模式使其可访问您的活动。
Not only do you not have to worry about holding onto it in your instance state, but you have a bit better control over the lifetime of those objects in memory. Instance state lifetime is controlled by Android; how long a Serviceholds onto the objects is controlled by you. Particularly if CustomObjectmight be big, or the list might be long, I would rather you have greater control over how long that RAM is consumed.
您不仅不必担心在实例状态中保留它,而且您可以更好地控制这些对象在内存中的生命周期。实例状态生命周期由 Android 控制;Service对对象的保持时间由您控制。特别是如果CustomObject可能很大,或者列表可能很长,我宁愿您更好地控制消耗 RAM 的时间。
回答by adamp
If this is primarily to handle orientation changes, could Activity#onRetainNonConfigurationInstance()do what you want?
如果这主要是为了处理方向变化,可以Activity#onRetainNonConfigurationInstance()做你想做的吗?
an activity can use this API to propagate extensive state from the old to new activity instance, from loaded bitmaps, to network connections, to evenly actively running threads. Note that you should not propagate any data that may change based on the configuration, including any data loaded from resources such as strings, layouts, or drawables.
活动可以使用此 API 将广泛的状态从旧的活动实例传播到新的活动实例,从加载的位图到网络连接,再到均匀运行的线程。请注意,您不应传播任何可能会根据配置更改的数据,包括从字符串、布局或可绘制对象等资源加载的任何数据。
This API won't help you if you're trying to do more than persist data across configuration changes.
如果您尝试做的不仅仅是跨配置更改保留数据,此 API 将无济于事。
回答by RaSchi
As far as I know, SavedInstanceStateis meant to save the UI configuration of the activity (like standard Android UI widgets, e.g. text field, are conserved automatically).
据我所知,SavedInstanceState是为了保存活动的 UI 配置(像标准的 Android UI 小部件,例如文本字段,会自动保存)。
If you want to save a custom object between different activity relaunches (this doesn't apply to the user-initiated finishing of an activity by clicking the back button, but it does apply e.g. for orientation changes). Use the following code to retain an object:
如果您想在不同的活动重新启动之间保存自定义对象(这不适用于用户通过单击后退按钮启动的活动完成,但它确实适用于例如方向更改)。使用以下代码保留一个对象:
// maintain a reference to the EchoServer object when the activity is recreated
@Override
public Object onRetainNonConfigurationInstance() {
return <<your object of choice>>;
}
And in the onCreate(Bundle savedInstanceState) method, you can then retrieve the object:
然后在 onCreate(Bundle savedInstanceState) 方法中,您可以检索对象:
// if there is a saved instance state, restore the state
if (savedInstanceState != null) {
<<yourObject>> = (<<your object's class) getLastNonConfigurationInstance();
回答by androidworkz
Why not just save the object to the SD Card? You can see an example of how I use this at my blog >> http://androidworkz.com/2010/07/06/source-code-imageview-flipper-sd-card-scanner/
为什么不直接将对象保存到 SD 卡?您可以在我的博客中查看我如何使用它的示例 >> http://androidworkz.com/2010/07/06/source-code-imageview-flipper-sd-card-scanner/
public void saveArray(String filename, String[] output_field) {
try {
FileOutputStream fos = new FileOutputStream(filename);
GZIPOutputStream gzos = new GZIPOutputStream(fos);
ObjectOutputStream out = new ObjectOutputStream(gzos);
out.writeObject(output_field);
out.flush();
out.close();
}
catch (IOException e) {
e.getStackTrace();
}
}
public String[] loadArray(String filename) {
try {
FileInputStream fis = new FileInputStream(filename);
GZIPInputStream gzis = new GZIPInputStream(fis);
ObjectInputStream in = new ObjectInputStream(gzis);
String[] read_field = (String[])in.readObject();
in.close();
return read_field;
}
catch (Exception e) {
e.getStackTrace();
}
return null;
}

