Proper Parcelable testing
Check out this Parcelable
I've just written:
public class Thing implements Parcelable {
public static final Parcelable.Creator<Thing> CREATOR =
new Parcelable.Creator<Thing>() {
public Thing createFromParcel(Parcel in) {
throw new RuntimeException("Oops");
}
// ...skipping boilerplate...
};
// ...so much boilerplate...
}
The RuntimeException
thrown in the middle of createFromParcel()
is a terrifyingly accurate simulation of poor code from my past.
It seems like you'd have a real bad time using this class, but you'd be surprised how hard it is to get it to crash. Check out my crappy Parcelable
in action in this simple Activity
:
public class MainActivity {
Thing thing = new Thing();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
thing = savedInstanceState.getParcelable("key");
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("key", thing);
}
}
Fire up the Activity and rotate the screen. Even though onCreate()
is called multiple times, it doesn't crash. How can that be? Shouldn't it crash the moment we call getParcelable()
?
The reason it doesn't crash is because sometimes, for optimization purposes, the system will reuse the exact same Parcelable
instance you passed into putParcelable()
, rather than going through the effort of creating a new object and unparcelling data. It's a nice optimization, but it means you can think your Parcelable
code is working when it's not.
Having run into this multiple times, here are my two best practices with regard to Parcelables
:
-
Don't write
Parcelable
code manually. Use a tool like auto-value-parcel to do it for you. You can't write better code than it will generate for you. -
If somehow the situation calls for artisanal, hand-crafted
Parcelables
, then test yourParcelables
using the "don't keep activities" developer option enabled. That way, you can guarantee that all yourParcelable
code is being exercised by switching back and forth between your app and another app.