Say I have a Java Bean object which is serializable. I want to store it away safely when an Activity goes through onDestroy() on purpose (i.e. onSaveInstanceState() is not called).
I am looking for a way which doesn't involve creating a database and write the object to that (mostly since a) Android's DB API is horrible and b) since databases make application updates a nightmare, because there is no decent support for applying migrations).
I thought about serializing the object to a ByteArrayOutputStream, base64 encode that and write it to a SharedPreferences file as a string. Or is that too far off?
UPDATE
Maybe that serialize-to-string idea wasn't that bad after all, seems to work out pretty well. Here's what I'm doing now:
public static String objectToString(Serializable object) { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { new ObjectOutputStream(out).writeObject(object); byte[] data = out.toByteArray(); out.close(); out = new ByteArrayOutputStream(); Base64OutputStream b64 = new Base64OutputStream(out); b64.write(data); b64.close(); out.close(); return new String(out.toByteArray()); } catch (IOException e) { e.printStackTrace(); } return null; } public static Object stringToObject(String encodedObject) { try { return new ObjectInputStream(new Base64InputStream( new ByteArrayInputStream(encodedObject.getBytes()))).readObject(); } catch (Exception e) { e.printStackTrace(); } return null; }
in onDestroy() I can then simply write the Base64 string to a preference file, where it's safe until I read it again during the next activity launch. It's a lot faster than I expected and unless your beans carry huge amounts of data, it works pretty well. And even better, you don't have to maintain a DB schema.
Still, I'm curious about how others do this.
I am looking for a way which doesn't involve creating a database and write the object to that (mostly since a) Android's DB API is horrible and b) since databases make application updates a nightmare, because there is no decent support for applying migrations).
Android's API is actually fairly reasonable, mostly because it's a thin wrapper over the SQLite API, and the SQLite API is fairly reasonable for an embedded database. Moreover, Android does provide assistance for schema upgrades on app upgrades, via SQLiteOpenHelper
.
It's a lot faster than I expected and unless your beans carry huge amounts of data, it works pretty well.
I have heard of many more developers running away screaming from serialization than I have heard of people having long term success with it. Just within the past few days, here on SO #android, I had an exchange with somebody trying desperately to rip serialization out of his app by the roots.
And even better, you don't have to maintain a DB schema.
Oh yes you do. What do you think is going to happen when you update your application and your class is modified? Doing the bookkeeping to figure out how to deserialize old versions of the class from a new version of a class is a chore and is one of the reasons developers abandon serialization. Also, do not forget that serialization is not transactional, whereas SQLite is.
I was also looking for a nice approach of un/marshalling any beans or activity states. We all know how much Activity's onStoreInstanceState() and onRestoreInstanceState() is a pain.
My acitivities simply store their states in onPause() and restore them in onCreate() lifecycle hooks via direct object serialization.
Serialization via a String like you do, is of course possible but less suitable for big data and causes a lot of overhead. Moreover Preferences are actually there to store preferences, not data :) Unfortunately, the Parcelable / Parcel what we could use for this purpose, does not recommend to store to persistent storage.
So what's left over is a simple object serialization - fortunately android SDK has implementation of the ObjectInputStream and ObjectOutputStream classes with all drawbacks and benefits - like we would also do in a non-android Java world, a simple:
ObjectOutputStream.writeObject(yourPojo)
would do the magic for us, (remember to implement the Serializable marker-interface)
Also, you may want to look in following APIs of a Context - ContextWrapper - Activity, which are very useful to cache local data (such as images) etc:
.getCacheDir() .getDir() .openFileInput() .openFileOutput()
happy hacking :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With