Dan Dan - 1 year ago 323
Android Question

Save Bundle to SharedPreferences

I've gone to great lengths to make all of the data for my Android game fit into a savedInstanceState Bundle. There's a lot of data altogether, including many Parcelable objects. This ensures that when the app is paused or the orientation changes, no data gets lost by the Activity being recreated.

However, I have just recently discovered that a savedInstanceState bundle is apparently NOT appropriate for long-term storage. So I'm looking for a way that I can adapt my existing save method to work as a long-term solution, so that the game state can always be restored.

I have heard of 2 solutions so far:

1) Use the savedInstanceState bundle for orientation changes, but also incorporate SharedPrefs for when the app needs to be shut down completely.

This seems incredibly counter-productive, as it uses 2 different completely methods to do basically the same thing. Also, since my savedInstanceState Bundle uses Parcelable objects, I would have to give each of those objects another method to enable them to be written to SharedPrefs. Essentially LOTS of duplicated and difficult-to-manage code.

2) Serialize the savedInstanceState Bundle and write it directly to a file.

I am open to this, but I don't actually know how to go about doing it. However, I'm still holding onto the hope that there may be a better solution, as I've heard that serialization in Android is "comically / unusably slow".

I would be extremely grateful if someone could provide me with a solution to this.

Dan Dan
Answer Source

I have now come up with my own solution to this problem, which is a semi-automatic means of saving Bundles to SharedPreferences. I say semi-automatic because, although saving the Bundle requires only one method, retrieving the data again and turning it back into a Bundle takes some work.

Here is the code to save the Bundle:

SharedPreferences save = getSharedPreferences(SAVE, MODE_PRIVATE);
Editor ed = save.edit();
saveBundle(ed, "", gameState);

 * Manually save a Bundle object to SharedPreferences.
 * @param ed
 * @param header
 * @param gameState
private void saveBundle(Editor ed, String header, Bundle gameState) {
    Set<String> keySet = gameState.keySet();
    Iterator<String> it = keySet.iterator();

    while (it.hasNext()){
        key = it.next();
        o = gameState.get(key);
        if (o == null){
            ed.remove(header + key);
        } else if (o instanceof Integer){
            ed.putInt(header + key, (Integer) o);
        } else if (o instanceof Long){
            ed.putLong(header + key, (Long) o);
        } else if (o instanceof Boolean){
            ed.putBoolean(header + key, (Boolean) o);
        } else if (o instanceof CharSequence){
            ed.putString(header + key, ((CharSequence) o).toString());
        } else if (o instanceof Bundle){
            saveBundle(header + key, ((Bundle) o));


Note that I have only written cases for the types I needed, but this should be easily adaptable if you have Bundles that also include other types.

This method will recursively save other Bundle objects stored inside the given Bundle. However, it will not work for Parcelable objects, so I had to alter my Parcelable objects to make them store themselves into a Bundle instead. Since Parcels and Bundles are pretty similar, this wasn't too hard. I think Bundles may also be slightly slower than Parcels, unfortunately.

I then wrote constructors in all of my previously-Parcelable objects to enable them to re-Bundle themselves from the data stored SharedPreferences. It's easy enough to reconstruct the keys to the data you need. Say you have the following data structure:

Bundle b {
    KEY_X -> int x;
    KEY_Y -> Bundle y {
                 KEY_Z -> int z;

These will be saved to SharedPreferences as follows:

KEY_X -> x

It may not be the prettiest method in the world, but it works, and it cost me much less code than the alternative, since now my onSaveInstanceState method and my onPause methods use the same technique.