Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.util.HashMap cannot be cast to java.util.LinkedHashMap #113

Open
ghost opened this issue Dec 28, 2017 · 2 comments
Open

java.util.HashMap cannot be cast to java.util.LinkedHashMap #113

ghost opened this issue Dec 28, 2017 · 2 comments

Comments

@ghost
Copy link

ghost commented Dec 28, 2017

I get an error "java.lang.ClassCastException" when restoring activity.

@State LinkedHashMap<Double, String[]> dropsMap;

Process: com.com.com, PID: 13985
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.com.com/com.com.com.CalculatorActivity}: java.lang.ClassCastException: java.util.HashMap cannot be cast to java.util.LinkedHashMap
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2947)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3008)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1650)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6688)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by: java.lang.ClassCastException: java.util.HashMap cannot be cast to java.util.LinkedHashMap
at com.com.com.CalculatorActivity$$Icepick.restore(CalculatorActivity$$Icepick.java:30)
at com.com.com.CalculatorActivity$$Icepick.restore(CalculatorActivity$$Icepick.java:11)
at icepick.Icepick.restoreInstanceState(Icepick.java:73)
at com.com.com.CalculatorActivity.onCreate(CalculatorActivity.java:156)
at android.app.Activity.performCreate(Activity.java:6912)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2900)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3008) 
at android.app.ActivityThread.-wrap14(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1650) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:154) 
at android.app.ActivityThread.main(ActivityThread.java:6688) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358) 

How can this be avoided?

@sergioserra
Copy link

sergioserra commented Jun 15, 2018

The problem is that when Android serializes the Bundle when saving or restoring the state, it only supports a subset of types: Integer, Long, String, Map, Bundle, List.

If you serialize an ArrayList of LinkedHashMap it will be restored as List and Map.
This is problematic if using LinkedHashMap because you loose the element ordering.

See: https://stackoverflow.com/questions/12300886/linkedlist-put-into-intent-extra-gets-recast-to-arraylist-when-retrieving-in-nex/12305459#12305459 for more details

You can use a custom bundler to avoid the problem:

Create a custom bundler:

public class LinkedHashmapBundler implements Bundler<LinkedHashMap> {

 @Override
 public void put(String s, LinkedHashMap val, Bundle bundle) {
    bundle.putSerializable(s, new Wrapper<>(val));
 }

 @SuppressWarnings("unchecked")
 @Override
 public LinkedHashMap get(String s, Bundle bundle) {
    return ((Wrapper<LinkedHashMap>) bundle.getSerializable(s)).get();
 }
} 

public class Wrapper<T extends Serializable> implements Serializable {
 private T wrapped;

 Wrapper(T wrapped) {
    this.wrapped = wrapped;
 }

 public T get() {
    return wrapped;
 }
} 

Use it like this:
@State(LinkedHashmapBundler.class) LinkedHasMap map

@oradkovsky
Copy link

Thank you, it works. I've noticed something strange. If you have project that uses android library and that library defines icepick processor and annotationProcessor, then icepick won't work inside the app's domain. Once annotationProcessor is duplicated to app module, everything works.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants