JozeRi
JozeRi

Reputation: 3429

Kotlin parcelable and arrayList of parcelables

I am trying to write a parcelable data object to pass to from activityA to activityB in my android application.

My object is passing with all the data, except my arraylist of the class Available Service

data class AvailableService(val id: Int,
                        val name: String,
                        val description: String,
                        val price: Double,
                        val currency: String,
                        val imageUrl: String) : Parcelable {

companion object {
    @JvmField @Suppress("unused")
    val CREATOR = createParcel { AvailableService(it) }
}

protected constructor(parcelIn: Parcel) : this(parcelIn.readInt(),
        parcelIn.readString(),
        parcelIn.readString(),
        parcelIn.readDouble(),
        parcelIn.readString(),
        parcelIn.readString())

override fun writeToParcel(dest: Parcel?, flags: Int) {
    dest?.writeInt(id)
    dest?.writeString(name)
    dest?.writeString(description)
    dest?.writeDouble(price)
    dest?.writeString(currency)
    dest?.writeString(imageUrl)
}

override fun describeContents() = 0
}

above is the available serviceClass, next I have Trip, which holds an arraylist of AvailableService.. I observed this in debug, it is successfully writing the arraylist, for some reason I have an issue with reading the data.

data class Trip(val id: String,
            val status: String,
            val orderedServices: ArrayList<OrderedService>) : Parcelable {

companion object {
    @JvmField @Suppress("unused")
    val CREATOR = createParcel { Trip(it) }
}

protected constructor(parcelIn: Parcel) : this(parcelIn.readString(),
        parcelIn.readString(),
        arrayListOf<OrderedService>().apply {
            parcelIn.readArrayList(OrderedService::class.java.classLoader)
        }
)

override fun writeToParcel(dest: Parcel?, flags: Int) {
    dest?.writeString(id)
    dest?.writeString(status)
    dest?.writeList(orderedServices)
}

override fun describeContents() = 0
}

in case someone wonders what's the fun of the CREATOR does, code below:

inline fun <reified T : Parcelable> createParcel(
    crossinline createFromParcel: (Parcel) -> T?): Parcelable.Creator<T> =
    object : Parcelable.Creator<T> {
        override fun createFromParcel(source: Parcel): T? = createFromParcel(source)
        override fun newArray(size: Int): Array<out T?> = arrayOfNulls(size)
    }

again, writing succeeds, but reading fails, I get an empty arraylist.. I think that part is the faulty one:

arrayListOf<OrderedService>().apply {
        parcelIn.readArrayList(OrderedService::class.java.classLoader)
    }

is there a different way to read/write arraylist? am I writing it wrong? reading it wrong?

thanks in advance for any help!

Upvotes: 26

Views: 31668

Answers (4)

Pratik Dodiya
Pratik Dodiya

Reputation: 2657

If Parent and Child model have parcelable then used below one

Parent Model

Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.createTypedArrayList(ImagesModel.CREATOR)
    )
}

override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeTypedList(images)
}

Upvotes: 3

John Codeos
John Codeos

Reputation: 1058

For API 29 and above

Replace:

arrayListOf<OrderedService>().apply {
    parcelIn.readArrayList(OrderedService::class.java.classLoader)
}

with

if (Build.VERSION.SDK_INT >= 29)
    parcel.readParcelableList(this, OrderedService::class.java.classLoader)
else
    parcel.readList(this as List<OrderedService>, OrderedService::class.java.classLoader)
}

and

override fun writeToParcel(dest: Parcel?, flags: Int) {
    dest?.writeString(id)
    dest?.writeString(status)
    dest?.writeList(orderedServices)
}

with

override fun writeToParcel(dest: Parcel?, flags: Int) {
    dest?.writeString(id)
    dest?.writeString(status)
    if (Build.VERSION.SDK_INT >= 29) {
        dest?.writeParcelableList(orderedServices,flags)
    } else {
        dest?.writeList(orderedServices as List<OrderedService>)
    }
}

Upvotes: 6

Ronaldo Albertini
Ronaldo Albertini

Reputation: 1339

Change

arrayListOf<OrderedService>().apply {
    parcelIn.readArrayList(OrderedService::class.java.classLoader)
}

to

source.createTypedArrayList(OrderedService.CREATOR)

Change dest?.writeList(orderedServices)

to dest?.writeTypedList(orderedServices)

The creator method

    companion object {
    @JvmField
    val CREATOR: Parcelable.Creator<Trip> = object : Parcelable.Creator<Trip> {
        override fun createFromParcel(source: Parcel): Trip = Trip(source)
        override fun newArray(size: Int): Array<Trip?> = arrayOfNulls(size)
    }
}

Upvotes: 7

Lid
Lid

Reputation: 456

Replace:

arrayListOf<OrderedService>().apply {
    parcelIn.readArrayList(OrderedService::class.java.classLoader)
}

with:

arrayListOf<OrderedService>().apply {
    parcelIn.readList(this, OrderedService::class.java.classLoader)
}

Upvotes: 42

Related Questions