ClassCastException when retrieving data from bundle on Android
Asked Answered
S

2

8

I have some state that I want to save accross the lifecycle of a fragment. It works fine when the screen rotates for example, but when the process has been killed and restored from disk (I think that's how it works), I get a ClassCastException. Here's some code:

Initialization:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
        playlistsMap = new LinkedHashMap<Section, List<Playlist>>();
    } else {
        playlistsMap = (LinkedHashMap<Section, List<Playlist>>) savedInstanceState.getSerializable(PLAYLISTS_MAP_KEY);
    }
    setHasOptionsMenu(true);
}

Saving the data :

@Override
public void onSaveInstanceState(Bundle outState) {
    if (isEverySectionsLoaded()) {
        outState.putSerializable(PLAYLISTS_MAP_KEY, playlistsMap);
    } else {
        outState.putSerializable(PLAYLISTS_MAP_KEY, new LinkedHashMap<Section, List<Playlist>>());
    }
    // ...
}

The exception I get from the cast in onCreate:

04-10 01:06:43.430 E/AndroidRuntime(28549): FATAL EXCEPTION: main
04-10 01:06:43.430 E/AndroidRuntime(28549): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mydomain.android/com.mydomain.android.ui.MainActivity}: 
java.lang.ClassCastException: java.util.HashMap cannot be cast to java.util.LinkedHashMap

I know it's better to use parcelables on Android, but I still don't understand how that could ever happen.

Any ideas?

Slovene answered 10/4, 2013 at 9:54 Comment(1)
In my case I have Hashtable saved across the savedInstanceState. When I rotate the screen, we get the hashtable but in case, the app crashes, as you have mentioned, we get a Hashmap and hence a class cast exception. Did you manage to find any good solution or workaround for this?Uneducated
S
11

Interesting read concerning a similar question can be found here

Any object that implements both java.util.List and java.io.Serializable will become ArrayList after intent.putExtra(EXTRA_TAG, suchObject)/startActivity(intent)/intent.getSerializableExtra(EXTRA_TAG).

I dare to say that the same counts for anything that implements serializable and map. That HashMap is the default you will get back.

A solution around this what seems like a bug would be something similar to:

private LinkedHashMap<Section, List<Playlist>> playlistsMap;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
        playlistsMap = new LinkedHashMap<Section, List<Playlist>>();
    } else {
        //assuming the bug returns a hashmap
        Map<Section, List<Playlist>> items = (Map<Section, List<Playlist>>) savedInstanceState.getSerializable(PLAYLISTS_MAP_KEY);

        //this way you can ensure you are working with a linkedHashMap. 
        //for the rest off the application
        playlistsMap.putAll(items);
    }
    setHasOptionsMenu(true);
}

The above code isn't tested but should work. This code will still work when the bug gets fixed due to the usage of interfaces. So you can rest assured when your client gets an android update that your code should still do the same instead of crashing and complaining that you cant cast a HashMap to a LinkedHashMap.

Schweiz answered 10/4, 2013 at 10:23 Comment(6)
Yes I know that LinkedHashMap and HashMap aren't interchangeable, I just don't know where the HashMap is coming from. The methods putSerializable/getSerializable aren't suposed to have any knowledge of what I'm putting it apart from the fact that they implement Serializable...Slovene
Mmhm, could be a bug in the android libraries itself then. I have read alot of people having similar problems as you. I have yet to find a an answer to "why" though. Ill keep looking and let you know if i find more. For a temporary solution, you could cast it to a Map. That should work, if it complains about casting to a HashMapSchweiz
Editted my answer with a link, that might be an interesting read.Schweiz
Ok, thanks for the link! That's one weird behavior for such a common task... Could you edit your post with just the relevant info so that I accept it and you can reap your points ?Slovene
@Slovene Editted my answer and added a sample of a fix that will hopefully help you or someone else with similar problems out.Schweiz
I've implemented something along the line of what I found in your link though because I needed the LinkedHashMap to keep the keys order.Slovene
G
-2

The problem is that the reference returned simply isn't a reference to an instance of LinkedHashMap. If function Return LinkedHashMap just returns a LinkedHashMap, it can't be cast to HashMap.

Godolphin answered 10/4, 2013 at 10:6 Comment(3)
I know what the classcastexception means, I just don't know where it's coming from. I'm putting a LinkedHashMap in the bundle as a Serializable, I expect bundle.getSerializable to return me the same object.Slovene
check where yo get LinkedHashMapGodolphin
and Passed it into HashMap.Godolphin

© 2022 - 2024 — McMap. All rights reserved.