如何以智能的方式将Java.util.Map编写成包?

我有一个string(键,值)的通用映射,这个字段是一个Bean的一部分,我需要可以parcelable。 所以,我可以使用Parcel#writeMap方法。 API Doc说:

请使用writeBundle(Bundle)。 在当前dataPosition()中将Map平铺到包中,如果需要,则增加dataCapacity()。 Map键必须是String对象。 Map值是使用writeValue(Object)写入的,并且必须遵循这个规范。 强烈build议使用writeBundle(Bundle)而不是此方法,因为Bundle类提供了一个types安全的API,可以避免编组时的神秘types错误。

所以,我可以迭代Map中的每一个条目,把它放到Bundle中,但是我仍然在寻找一个更聪明的方法。 我缺lessAndroid SDK中的任何方法吗?

目前我这样做:

final Bundle bundle = new Bundle(); final Iterator<Entry<String, String>> iter = links.entrySet().iterator(); while(iter.hasNext()) { final Entry<String, String> entry =iter.next(); bundle.putString(entry.getKey(), entry.getValue()); } parcel.writeBundle(bundle); 

我最终做了一点不同。 它遵循你所期待的处理可分割的模式,所以它应该是熟悉的。

 public void writeToParcel(Parcel out, int flags){ out.writeInt(map.size()); for(Map.Entry<String,String> entry : map.entrySet()){ out.writeString(entry.getKey()); out.writeString(entry.getValue()); } } private MyParcelable(Parcel in){ //initialize your map before int size = in.readInt(); for(int i = 0; i < size; i++){ String key = in.readString(); String value = in.readString(); map.put(key,value); } } 

在我的应用程序中,地图中按键的顺序非常重要。 我正在使用LinekdHashMap来保存sorting,并以此方式保证键在从包中提取后将以相同的顺序出现。

你可以试试:

 bundle.putSerializable(yourSerializableMap); 

如果你select的映射实现了可序列化(比如HashMap),那么你可以轻松使用你的writeBundle

如果地图的keyvalue都扩展了Parcelable ,那么可以有一个非常漂亮的generics解决scheme:

 // For writing to a Parcel public <K extends Parcelable,V extends Parcelable> void writeParcelableMap( Parcel parcel, int flags, Map<K, V > map) { parcel.writeInt(map.size()); for(Map.Entry<K, V> e : map.entrySet()){ parcel.writeParcelable(e.getKey(), flags); parcel.writeParcelable(e.getValue(), flags); } } // For reading from a Parcel public <K extends Parcelable,V extends Parcelable> Map<K,V> readParcelableMap( Parcel parcel, Class<K> kClass, Class<V> vClass) { int size = parcel.readInt(); Map<K, V> map = new HashMap<K, V>(size); for(int i = 0; i < size; i++){ map.put(kClass.cast(parcel.readParcelable(kClass.getClassLoader())), vClass.cast(parcel.readParcelable(vClass.getClassLoader()))); } return map; } 

用法

 // MyClass1 and MyClass2 must extend Parcelable Map<MyClass1, MyClass2> map; // Writing to a parcel writeParcelableMap(parcel, flags, map); // Reading from a parcel map = readParcelableMap(parcel, MyClass1.class, MyClass2.class); 

好问题。 除了putSerializable和writeMap之外,我知道API中没有任何方法。 出于性能的原因, build议不要使用序列化,并且也不build议使用writeMap(),因为您已经指出了一些神秘的原因。

我今天需要打包一个HashMap,所以我试着用一些推荐的方法来编写一些实用的方法来将Parcell Map映射到Bundle或从Bundle中导出:

 // Usage: // read map into a HashMap<String,Foo> links = readMap(parcel, Foo.class); // another way that lets you use a different Map implementation links = new SuperDooperMap<String, Foo>; readMap(links, parcel, Foo.class); // write map out writeMap(links, parcel); //////////////////////////////////////////////////////////////////// // Parcel methods /** * Reads a Map from a Parcel that was stored using a String array and a Bundle. * * @param in the Parcel to retrieve the map from * @param type the class used for the value objects in the map, equivalent to V.class before type erasure * @return a map containing the items retrieved from the parcel */ public static <V extends Parcelable> Map<String,V> readMap(Parcel in, Class<? extends V> type) { Map<String,V> map = new HashMap<String,V>(); if(in != null) { String[] keys = in.createStringArray(); Bundle bundle = in.readBundle(type.getClassLoader()); for(String key : keys) map.put(key, type.cast(bundle.getParcelable(key))); } return map; } /** * Reads into an existing Map from a Parcel that was stored using a String array and a Bundle. * * @param map the Map<String,V> that will receive the items from the parcel * @param in the Parcel to retrieve the map from * @param type the class used for the value objects in the map, equivalent to V.class before type erasure */ public static <V extends Parcelable> void readMap(Map<String,V> map, Parcel in, Class<V> type) { if(map != null) { map.clear(); if(in != null) { String[] keys = in.createStringArray(); Bundle bundle = in.readBundle(type.getClassLoader()); for(String key : keys) map.put(key, type.cast(bundle.getParcelable(key))); } } } /** * Writes a Map to a Parcel using a String array and a Bundle. * * @param map the Map<String,V> to store in the parcel * @param out the Parcel to store the map in */ public static void writeMap(Map<String,? extends Parcelable> map, Parcel out) { if(map != null && map.size() > 0) { /* Set<String> keySet = map.keySet(); Bundle b = new Bundle(); for(String key : keySet) b.putParcelable(key, map.get(key)); String[] array = keySet.toArray(new String[keySet.size()]); out.writeStringArray(array); out.writeBundle(b); /*/ // alternative using an entrySet, keeping output data format the same // (if you don't need to preserve the data format, you might prefer to just write the key-value pairs directly to the parcel) Bundle bundle = new Bundle(); for(Map.Entry<String, ? extends Parcelable> entry : map.entrySet()) { bundle.putParcelable(entry.getKey(), entry.getValue()); } final Set<String> keySet = map.keySet(); final String[] array = keySet.toArray(new String[keySet.size()]); out.writeStringArray(array); out.writeBundle(bundle); /**/ } else { //String[] array = Collections.<String>emptySet().toArray(new String[0]); // you can use a static instance of String[0] here instead out.writeStringArray(new String[0]); out.writeBundle(Bundle.EMPTY); } } 

编辑:修改writeMap使用entrySet,同时保留与我原来的答案相同的数据格式(显示在切换注释的另一侧)。 如果你不需要或者不想保持读兼容性,那么在每次迭代中存储键值对可能会更简单,就像@ bcorso和@Anthony Naddeo的答案一样。