【问题标题】:Android LinkedHashMap deserializing as HashMap, causes CCE errorAndroid LinkedHashMap 反序列化为 HashMap,导致 CCE 错误
【发布时间】:2014-09-10 17:21:37
【问题描述】:

我试图在活动之间传递一个序列化的 LinkedHashMap,当我反序列化对象时得到一个令人困惑的结果/错误。

我将对象序列化如下:

    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?

附:我试图包含所有相关的内容,但如果我遗漏了任何重要的内容,我可以添加更多代码。

【问题讨论】:

  • 我的代码已经运行了 15 周。突然间,我突然冒出这个异常。 Parcelable 也无缘无故地崩溃了。我猜他们在某处破坏了一些代码。
  • 我遇到了同样的问题,在android 5.0或更高版本中测试代码后开始出现此错误。我必须实施类似this one 的解决方法
  • Android 在通过Bundle 序列化/反序列化时将LInkedHashMap 转换为Hashmap。有关更多详细信息,请参阅我对这个问题和链接问题的回答:stackoverflow.com/a/38960732/769265

标签: android serialization classcastexception linkedhashmap


【解决方案1】:

我采用了另一种方法:将任何(类型的)Map 序列化为 2 个 ArrayList:一个包含键,另一个包含值。这样,映射条目的顺序(在 LinkedHashMap 中很重要)得以保留。

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

映射 -> 2 个数组列表:

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 ArrayLists -> 特定类型的映射

 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 Bundle 助手:

 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);
    }

用法:

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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-22
    • 2011-08-26
    • 1970-01-01
    • 2012-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多