Be Careful Where You Use Custom Parcelables

Custom Parcelable classes — ones unique to your app, not a part of the Android framework — have had intermittent problems over the years when used as Intent extras. Basically, if a core OS process needs to modify the Intent extras, that process winds up trying to recreate your Parcelable objects as part of setting up the extras Bundle for modification. That process does not have your class and so it gets a runtime exception.

One area where this can occur is with AlarmManager . Code that used custom Parcelable objects with AlarmManager that might have worked on older versions of Android will not work on Android N.

Completely in-process uses of custom Parcelable objects, such as extras on LocalBroadcastManager Intents , is safe. Using custom Parcelables in the saved instance state Bundle should be safe.

UPDATE 25 July 2016: Apparently, I spoke too soon on the saved instance state Bundle . Usually, that is OK. For whatever reason, Maps V2 screws it up. Many thanks to Olivier Lefevre for pointing this out!

The further afield from that you get — including any place where you might distribute a PendingIntent — be careful and be sure to test thoroughly.

One workaround, such as it is, is to load the data from persistent storage when needed, perhaps using a process-level cache if your process still happens to be around. So, for example, suppose you used PendingIntent.getBroadcast() with AlarmManager . Rather than put a custom Parcelable in the Intent extra, just include enough key data to know what you need. Then, as part of processing the alarm event, go grab that data from cache or storage.

Another approach is to switch from Parcelable to “bundleable”: convert your object to and from a Bundle , sticking to framework-defined classes for all the contents of the Bundle . Since all the classes are available to all relevant processes, you should not run into the sort of problem that you get from custom Parcelable classes.

I assume that the problem with Parcelable will also affect Serializable , though I am not certain of that.

UPDATE 23 July 2016: Matthias Urhahn pointed out another workaround: convert the Parcelable into a byte[] yourself, storing that in the Bundle . Then, the OS process will just treat it as some random byte[] . This Stack Overflow answer shows the technique.

Learn second-generation Android app development — with Kotlin and the Android Jetpack — through CommonsWare’s Android app development training!

— Jul 22, 2016