Android LinkedHashMap deserializing as HashMap, causes CCE error

随声附和 提交于 2019-12-06 06:10:53

I went for a different approach: serialize any (type of) Map into 2 ArrayLists: one containing the keys and the other one containing the values. This way, the order of the map entries (important in a LinkedHashMap) is kept.

Each key/value implements Serializable. If you know for sure you need just Strings or just one particular type of Map, then it should be really easy to convert the following generic code into the scenario needed which also simplifies the complexity.

Map -> 2 ArrayLists:

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 -> Map of a specific type

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

Helpers for Android's 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);
    }

Usage:

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);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!