When a Serializable object is placed in an android.os.Bundle, certain types whose serialization is handled with custom logic are ‘flattened’ to their base types. Casting items retrieved from a bundle with bundle.getSerializable(...) back to their original types may therefore cause a ClassCastException.
See discussion here.
Casting the result of bundle.getSerializable(...) to any subtype of any of the following classes is forbidden[^1]:
Map (except HashMap)List (except ArrayList or any Parcelable)SparseArray (except Parcelables)CharSequence (except String or any Parcelable)CharSequence[] (except String[])Note that getSerializable happens to return HashMaps for any Map implementation or ArrayLists for any List implementation, however, this is not guaranteed by the API. Therefore, casting to ArrayList or HashMap is allowed, but it is safer to cast to the base List or Map.
An exception is made for most types if they also implement Parcelable, as they are handled such that their type is preserved.
In many cases, you may be able to cast your object to its base type without any ill effects if you don't require any features of a specific implementation.
In other cases, there may be an constructor that will create an instance of your type from an instance of the base type (but beware of null results causing IllegalArgumentExceptions!) For example:
TreeMap<K, V> myMap; Map<K, V> deserialized = (Map<K, V>) myBundle.getSerializable("KEY"); myMap = deserialized == null ? null : new TreeMap<K, V>(deserialized);
If you really need a different workaround, wrapping your object (e.g. of type MyList) in an arbitrary wrapper class (e.g. MyListHolder) that implements just Serializable will serialize and deserialize it through the standard Serializable path and preserve your original type.
[^1]: Here is a full list of types that are handled specially in the bundling/parceling serialization/deserialization process, in order of precedence. If a serialized object inherits from multiple types on this list, it will be bundled as the first of those types to appear. e.g. if an object implements both Parcelable and List, it will be serialized as a Parcelable rather than a List, and its type will be preserved. Note also that it is okay to cast to String even though it inherits from CharSequence since String is handled first.
* `String`
* `Integer`
* `Map`
* `Bundle`
* `PersistableBundle`
* `Parcelable` - Parcelables are handled such that their type is
preserved.
* `Short`
* `Long`
* `Float`
* `Double`
* `Boolean`
* `CharSequence`
* `List`
* `SparseArray`
* `boolean[]`
* `byte[]`
* `String[]`
* `CharSequence[]`
* `IBinder`
* `Parcelable[]`
* `int[]`
* `long[]`
* `Byte`
* `Size`
* `SizeF`
* `double[]`
* `Object[]` - Only handles pure Object[], not subtypes.
* All other `Serializable` objects go through the normal serialization
path, types are preserved.