lannyf
lannyf

Reputation: 11025

kotlin, how to put HashMap in Parcelable

In a class who implements Parcelable it has a HashMap member.

Saw Parcelable has public final void readMap(Map outVal, ClassLoader loader), but could not find a sample to use it.

If do it by flatten the map and write/read one by one accordingly, how to extract from the parcel in the constructor? (got error to build the map from the parcelable, cannot access buildTheMap() before constructor is called)

class CachedData(val type: Int,
             val name: String,
             val details: HashMap<String, String) :
    Parcelable {

constructor(parcel: Parcel) : this(
        parcel.readInt(),
        parcel.readString(),

        // how to get the hashMap out of the parcel???
        buildTheMap(parcel)   //<=== cannot access buildTheMap() before constructor is called
)

fun buildTheMap(parcel: Parcel) :HashMap<String, String> {

    val size = parcel.readInt()
    val map = HashMap<String, String>()

    for (i in 1..size) {
        val key = parcel.readString()
        val value = parcel.readString()
        map[key] = value
    }
    return map
}

override fun writeToParcel(parcel: Parcel, flags: Int) {
    parcel.writeInt(type)
    parcel.writeString(name)

    // how to write the HashMap<String, String> to the parcel
    //parcel.???

    parcel.writeInt(details.size)
    for ((key, value) in details) {
        parcel.writeString(key)
        parcel.writeString(value)
    }
}

override fun describeContents(): Int {
    return 0
}

companion object {
    @JvmField val CREATOR: Parcelable.Creator<CachedData> = object : Parcelable.Creator<CachedData>{
        override fun createFromParcel(parcel: Parcel): CachedData {
            return CachedData(parcel)
        }

        override fun newArray(size: Int): Array<CachedData?> {
            return arrayOfNulls(size)
        }
    }
}

}

Upvotes: 3

Views: 5844

Answers (3)

Alexey Romanov
Alexey Romanov

Reputation: 170713

Use @Parcelize and just write

@Parcelize
class CachedData(val type: Int, val name: String, val details: HashMap<String, String>) : Parcelable

It has built-in support for HashMap (and other collection types).

Upvotes: 3

lannyf
lannyf

Reputation: 11025

Still hope some to share how to use the readMap().

Here is the kotlin version to flatten the map, for reference.

class CachedData :
    Parcelable {

var type: Int = 0
var name: String = ""
var details: HashMap<String, String> = HashMap()

constructor (type: Int,
             name: String,
             details: HashMap<String, String>) {
    this.type = type
    this.name = name
    this.details = details
}

constructor(parcel: Parcel) {
    this.type = parcel.readInt()
    this.name = parcel.readString()
    this.details = buildTheMap(parcel)
}

fun buildTheMap(parcel: Parcel): HashMap<String, String> {

    val size = parcel.readInt()
    val map = HashMap<String, String>(size)

    for (i in 1..size) {
        val key = parcel.readString()
        val value = parcel.readString()
        map[key] = value
    }
    return map
}

fun writeToMap(parcel: Parcel) {
    parcel.writeInt(details.size)
    for ((key, value) in details) {
        parcel.writeString(key)
        parcel.writeString(value)
    }
}

override fun writeToParcel(parcel: Parcel, flags: Int) {
    parcel.writeInt(type)
    parcel.writeString(name)
    writeToMap(parcel)
}

override fun describeContents(): Int {
    return 0
}

companion object {
    @JvmField
    val CREATOR: Parcelable.Creator<CachedData> = object : Parcelable.Creator<CachedData> {
        override fun createFromParcel(parcel: Parcel): CachedData {
            return CachedData(parcel)
        }

        override fun newArray(size: Int): Array<CachedData?> {
            return arrayOfNulls(size)
        }
    }
}
} 

Upvotes: 5

Serg Burlaka
Serg Burlaka

Reputation: 2496

As for me a faced with the same problem. The working for me solution was:

public class JoustBattler extends Parcelable {

...

 private Map<String, Integer> battleWins;


 protected JoustBattler(Parcel in) {
        super(in);

        int battleWinsSize = in.readInt();
        this.battleWins = new HashMap<String, Integer>(battleWinsSize);
        for (int i = 0; i < battleWinsSize; i++) {
            String key = in.readString();
            Integer value = (Integer) in.readValue(Integer.class.getClassLoader());
            this.battleWins.put(key, value);
        }

    }


    @Override
    public void writeToParcel(Parcel dest, int flags) {
        super.writeToParcel(dest, flags);

        dest.writeInt(this.battleWins.size());
        for (Map.Entry<String, Integer> entry : this.battleWins.entrySet()) {
            dest.writeString(entry.getKey());
            dest.writeValue(entry.getValue());
        }

    }

Hope it helps, good luck!

Upvotes: 6

Related Questions