2014-09-10 123 views
2

我试图在活动之间传递一个序列化的LinkedHashMap,并且在反序列化对象时得到一个令人困惑的结果/错误。Android LinkedHashMap反序列化为HashMap,导致CCE错误

序列化对象如下:

Bundle exDetails = new Bundle(); 
    LinkedHashMap<String, Exercise> exMap = new LinkedHashMap<String, 
    Exercise (workout.getExercises()); 

    exDetails.putString(WORKOUTNAME, workout.getWorkoutName()); 
    exDetails.putSerializable(workout.getWorkoutName(), exMap); 

    iComplete.putExtra("wName", exDetails); 
    startActivity(iComplete); 

这似乎很好地工作,这个问题表明了在未来的活动:

Bundle exDetails = getIntent().getBundleExtra("wName"); 
    workoutName = exDetails.getString(WORKOUTNAME); 
    Serializable eData = exDetails.getSerializable(workoutName); 

    ex = new LinkedHashMap<String, Exercise>(); 
    ex = (LinkedHashMap<String, Exercise>) eData; 

此时,反序列化对象(EDATA)包含一个HashMap对象(不是LinkedHashMap),它给我在最后一行上的

java.lang.ClassCastException:java.util.HashMap cannot be 
cast to java.util.LinkedHashMap 

。我已经通过调试器验证了包(在第二个活动中)包含一个HashMap,而不是LinkedHashMap(因为我假设它应该)。我还应该提到,我需要维护向Map中添加条目的顺序,因此需要使用LinkedHashMap。这些条目最终会打印出来,顺序对输出非常重要。

问题: 我是否做了特别错误的事情,还是由于LinkedHashMap的序列化错误导致此问题?我注意到一些类似的线程,似乎说这是几个Map实现的持续问题。他们没有直接回答我的问题。

如果是后者,是否有一个解决方法不是太先进(我不是远远超出初学者水平,但我愿意尝试大多数事情),还是我只需要咬紧牙关就行了除了LinkedHashMap以外的东西?

P.s.我试图包含所有相关内容,但如果我忽略了任何重要的内容,我可以添加更多代码。

+0

我的代码一直工作正常。突然之间,我有了这个例外,无处不在。由于没有明显的原因,Parcelable也在崩溃。我猜他们在某处销毁了一些代码。 – 2014-12-11 13:18:01

+0

我有相同的问题,并且在测试Android 5.0或更高版本中的代码后,此错误开始出现。我不得不实施一个像[这一个](http://stackoverflow.com/questions/15922572/classcastexception-when-retrieving-data-from-bundle-on-android)的解决方法 – Juancho 2015-05-18 13:38:14

+0

Android将'LInkedHashMap'转换为'当它通过'Bundle'被序列化/反序列化时,它就是'Hashmap'。看到我的回答这个问题和更多血淋淋的细节链接的问题:http://stackoverflow.com/a/38960732/769265 – 2016-08-15 18:48:36

回答

0

我采用了不同的方法:将任何(类型)Map映射为2个ArrayLists:一个包含键,另一个包含值。这样,地图条目的顺序(在LinkedHashMap中很重要)就被保留下来了。

每个键/值实现Serializable。如果您确实知道只需要字符串或者只是一种特定类型的Map,那么将以下通用代码转换为所需的方案应该非常容易,这也简化了复杂性。

地图 - > 2周的ArrayList:

public static <K extends Serializable, V extends Serializable> Pair<ArrayList<K>, ArrayList<V>> convertMapToArrays(@NonNull Map<K, V> map) { 
     final Set<Map.Entry<K, V>> entries = map.entrySet(); 
     final int size = entries.size(); 
     final ArrayList<K> keys = new ArrayList<>(size); 
     final ArrayList<V> values = new ArrayList<>(size); 
     for (Map.Entry<K, V> entry : entries) { 
      keys.add(entry.getKey()); 
      values.add(entry.getValue()); 
     } 
     return new Pair<>(keys, values); 
} 

2的ArrayList - >特定类型的地图

public static <K extends Serializable, V extends Serializable> Map<K, V> convertArraysToMap(@NonNull ArrayList<K> keys, @NonNull ArrayList<V> values, @NonNull Class<? extends Map<K, V>> mapClass) { 
     if (keys.size() != values.size()) { 
      throw new RuntimeException("keys and values must have the same number of elements"); 
     } 
     final int size = keys.size(); 
     Map<K, V> map; 
     try { 
      final Constructor<? extends Map<K, V>> constructor = mapClass.getConstructor(Integer.TYPE); 
      map = constructor.newInstance(size); 
     } catch (Exception nse) { 
      throw new RuntimeException("Map constructor that accepts the initial capacity not found."); 
     } 

     for (int i = 0; i < size; i++) { 
      final K key = keys.get(i); 
      final V value = values.get(i); 
      map.put(key, value); 
     } 
     return map; 
    } 

助手Android版的软件包:

public static <K extends Serializable, V extends Serializable> void saveMapToBundleAsArrays(@NonNull Map<K, V> map, @NonNull String key, @NonNull Bundle bundle) { 
     final Pair<ArrayList<K>, ArrayList<V>> mapToArrays = convertMapToArrays(map); 
     final String keyForKeys = key + "_keys"; 
     final String keyForValues = key + "_values"; 
     bundle.putSerializable(keyForKeys, mapToArrays.first); 
     bundle.putSerializable(keyForValues, mapToArrays.second); 
    } 

public static Map<Serializable, Serializable> loadMapFromBundle(@NonNull Bundle bundle, @NonNull String key, @NonNull Class<? extends Map<Serializable, Serializable>> mapClass) { 
     final String keyForKeys = key + "_keys"; 
     final String keyForValues = key + "_values"; 
     final ArrayList<Serializable> keys = (ArrayList<Serializable>) bundle.getSerializable(keyForKeys); 
     final ArrayList<Serializable> values = (ArrayList<Serializable>) bundle.getSerializable(keyForValues); 
     return convertArraysToMap(keys, values, mapClass); 
    } 

用法:15周

saveMapToBundleAsArrays(mModelEvolution, KEY_MODEL_DATA, bundle); 

Class<LinkedHashMap<Serializable, Serializable>> linkedHashMapClazz = 
       (Class<LinkedHashMap<Serializable, Serializable>>) new LinkedHashMap<String, String>().getClass(); 
mModelEvolution = (LinkedHashMap) ObjectUtils.loadMapFromBundle(bundle, KEY_MODEL_DATA, linkedHashMapClazz);