Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save custom object array in instance state

I have a List<CustomObject> (where CustomObject comes 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:

outState.putSerializable(KEY, (ArrayList<CustomObject>) myList); // because myList is instantiated as an ArrayList
outState.putSerializable(KEY, myList.toArray());

Both options work when switching orientation on the phone (yes, onSaveInstanceState is 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:

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.access$2400(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?

like image 995
Felix Avatar asked Jul 11 '10 12:07

Felix


2 Answers

Make your CustomObject implement Parcelable and use:

outState.putParcelable(KEY, myList);
onSaveInstanceState(outState);

Also check this tutorial.

EDIT after CommonsWare comment:

If your CustomObject doesn't implement Serializable or Parcelable I would try wrapping it inside an object of your own and add:

  • private void readObject(ObjectInputStream aStream) throws IOException, ClassNotFoundException { /*Your deserialization */ }
  • private void writeObject(ObjectOutputStream aStream) throws IOException { /*Your serialization */}
like image 50
Macarse Avatar answered Nov 10 '22 05:11

Macarse


Have your List<CustomObject> be held by a service and make it accessible to your activities via the local binding pattern.

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 Service holds onto the objects is controlled by you. Particularly if CustomObject might be big, or the list might be long, I would rather you have greater control over how long that RAM is consumed.

like image 5
CommonsWare Avatar answered Nov 10 '22 03:11

CommonsWare