سؤال

I'm trying to pass a Hashmap of custom objects through an intent.

I am trying to use parcelable as that's what i read is the correct way to do things in android (i.e. parcelable over serializable).

However, when i try and get the hashmap using getParcelable, it can't find my hashmap in the intent, but getSerializable can.

Is it OK to use serializable for hashmaps? Is this my only option?

هل كانت مفيدة؟

المحلول

You can of course serialize your map, as long as your Objects are serializable. What you also could do is creating a separate singleton class (DataStore or so?) that saved your data. This way you don't need to pass the data from Activity to Activity. Or, even simpler, save the data in a public static variable.

نصائح أخرى

java.util.HashMap is not Parcelable, so your options are:

  • use put/getSerializable, which will work fine within your app
  • encode the HashMap as json or another remotable format if sending outside your app
  • take out the map entries one by one and put them in the Bundle directly (assuming they have string keys)

You have to add a "wrapper". It is ugly but working...

/**
 * Provides a way to wrap a serializable {@link Map} in order to preserve its class
 * during serialization inside an {@link Intent}, otherwise it would be "flattened"
 * in a {@link android.os.Parcel} and unparceled as a {@link java.util.HashMap}.
 */
public class MapWrapper<T extends Map & Serializable> implements Serializable {

    private final T map;

    public MapWrapper(@NonNull T map) {
        this.map = map;
    }

    public T getMap() {
        return map;
    }

    /**
     * Add extra map data to the intent. The name must include a package prefix, for example
     * the app com.android.contacts would use names like "com.android.contacts.ShowAll".
     * <p>
     * The provided map will be wrapped to preserve its class during serialization.
     * Use {@link #getMapExtra(Intent, String)} to deserialize it.
     *
     * @param intent The intent to add data to.
     * @param name   The name of the extra data, with package prefix.
     * @param map    The map data value.
     *
     * @return The same {@link Intent} object, for chaining multiple calls into a single statement.
     *
     * @see Intent#putExtra(String, Serializable)
     */
    @NonNull
    public static <T extends Map & Serializable> Intent putMapExtra(
            @NonNull Intent intent, @NonNull String name, @NonNull T map) {
        return intent.putExtra(name, new MapWrapper<>(map));
    }

    /**
     * Retrieve extra map data from the intent.
     *
     * @param intent The intent to retrieve data from.
     * @param name   The name of the desired extra item.
     *
     * @return The value of an extra map item that was previously added with
     * {@link #putMapExtra(Intent, String, Map)} or {@code null} if no data was found.
     *
     * @throws ClassCastException
     * If the {@link Serializable} object with the specified name is not of type
     * {@link MapWrapper} or if the wrapped {@code Map} is not of type {@link T}.
     * 
     * @see Intent#getSerializableExtra(String)
     */
    @Nullable
    public static <T extends Map & Serializable> T getMapExtra(
            @NonNull Intent intent, @NonNull String name)
            throws ClassCastException {
        final Serializable s = intent.getSerializableExtra(name);
        //noinspection unchecked
        return s == null ? null : ((MapWrapper<T>)s).getMap();
    }

}

More informations on https://medium.com/the-wtf-files/the-mysterious-case-of-the-bundle-and-the-map-7b15279a794e

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top