Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does saving a Hashtable of non-Parcelable objects in onSaveInstanceState() sometimes work?

After going through an introductory Android programming book, I wanted to alter the example application in order to solidify my understanding of some topics that weren't really covered. In making the change, I made an error, but I'm curious why the error worked in some cases but not in others.

An activity within the application stores a series of questions in a Hashtable<Integer, Question>, where Question is a small class holding an int and two Strings. As originally written, the activity downloads the questions from a server on every onCreate(), so I wanted to implement onSaveInstanceState() to prevent some redundant downloads. onSaveInstanceState() saves the Hashtable into the Bundle using putSerializable().

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

It worked perfectly for screen orientation changes even before I knew what a Parcelable was or how to implement one. I only knew there was a problem when I pressed the emulator's home key and the app silently, invisibly crashed with no LogCat output. The stack trace led me to look up Parcelable and make Question implement it.

My question isn't what I did wrong. The question is this: When the Question class did not implement Parcelable, why did the app crash only on pressing Home and not on a screen orientation change?

like image 432
erichamion Avatar asked Mar 03 '11 21:03

erichamion


2 Answers

As far as I understand Android doesn't serialize an instance state when recreating an activity after configuration changes. That's why your code works. Persisted objects just don't need to be parcelable because they exist in memory only.

This looks like an optimization. Android knows that the process will not be terminated in this case and there's no need to save the instance state to a file. (In theory the process can be terminated during the configuration change and I don't really know how Android solves this problem).

But when the user presses Home key your app becomes background. And its process can be terminated in case of low memory. Android needs to save activity's state to a file in order to be able to restore your app and its activities in future. In this case the instance state is really serialized and saved to a persistent storage. And that's why your code doesn't work.

Process termination can occur at any moment so you can't rely on some implementation details. Just make instance state parcelable or serializable and you will not face this problem again.

like image 153
Michael Avatar answered Nov 15 '22 05:11

Michael


Quoting Steve Moseley

Note that it is NOT safe to use onSaveInstanceState and onRestoreInstanceState, according to the documentation on Activity states in http://developer.android.com/reference/android/app/Activity.html.

The document states (in the 'Activity Lifecycle' section):

Note that it is important to save persistent data in onPause() instead of onSaveInstanceState(Bundle) because the later is not part of the lifecycle callbacks, so will not be called in every situation as described in its documentation.

In other words, put your save/restore code in onPause() and onResume() instead!

like image 29
Sherif elKhatib Avatar answered Nov 15 '22 04:11

Sherif elKhatib