13

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?

5 Answers 5

6

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 */}
Sign up to request clarification or add additional context in comments.

2 Comments

Felix indicated that he cannot modify CustomObject.
I marked this as accepted because this is the route I would go. However, I spoke with the authors of the library and they'll be implementing it.
5

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.

5 Comments

You mean having a Service started all the time which doesn't stop?
It doesn't stop while there are 1+ activities running. It would shut down once there are no more bound connections. You could also use a custom Application object, if you prefer -- you lose control but don't have a Service lying about.
@CommonsWare: I guess he wants to Serialize to save it for later. Using that approach he will lose the info if the phone gets rebooted.
@Macarse: Felix is trying to get his objects working with onSaveInstanceState(). I am suggesting he simply avoid onSaveInstanceState() with these objects. Whether he uses Serializable for other purposes (e.g., some sort of "save" operation), has no bearing on my suggestion. onSaveInstanceState() is not a persistence mechanism, in any circumstance.
Thanks for the idea, but I think it would be a bit cumbersome. Also, it would require a lot of refactoring my app.
1

If this is primarily to handle orientation changes, could Activity#onRetainNonConfigurationInstance() do what you want?

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.

This API won't help you if you're trying to do more than persist data across configuration changes.

1 Comment

+1, I knew about onRetainNonConfigurationInstance(), but no, it's not primarily for orientation changes.
0

As far as I know, SavedInstanceState is meant to save the UI configuration of the activity (like standard Android UI widgets, e.g. text field, are conserved automatically).

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:

    // if there is a saved instance state, restore the state
    if (savedInstanceState != null) {
        <<yourObject>> = (<<your object's class) getLastNonConfigurationInstance();

1 Comment

The method onRetainNonConfigurationInstance is deprecated as of API 13. developer.android.com/reference/android/app/…
-2

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/

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;
      }

1 Comment

Because... my object is custom and can't be serialized in order to be stored on the SD card?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.