Search code examples
androidkotlinclassnotfoundexceptionunmarshallingparcelable

Android Parcelable Issue - ClassNotFoundException when Unmarshalling


I have an object list as follows:

data class MyProduct(
    var id: String?,
    var name: String?
) : Parcelable {

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

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<MyProduct> {
        override fun createFromParcel(parcel: Parcel) = MyProduct(
            id = parcel.readString(),
            name = parcel.readString(),
        )

        override fun newArray(size: Int): Array<MyProduct?> = arrayOfNulls(size)
    }
}

MutableList<MyProduct>

I need to share this using an event broadcaster. I have a method as follows:

    fun sendMyProduct(myProducts: MutableList<MyProduct>) {
        intentBroadcaster.broadcastMessage(
            event = EVENT_MY_PRODUCTS,
            data = MyProductsUpdated(
                myProducts = myProducts
            )
        )
    }

MyProductsUpdated is a parcelable class.

data class MyProductsUpdated(
    val myProducts: MutableList<MyProduct>
) : Event {

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeList(myProducts)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<MyProductsUpdated> {
        override fun createFromParcel(parcel: Parcel) = MyProductsUpdated(
            myProducts = parcel.readParcelable(MyProduct::class.java.classLoader)!!
        )

        override fun newArray(size: Int): Array<MyProductsUpdated?> = arrayOfNulls(size)
    }
}

When I need to retrieve the data after broadcast I am doing the following:

    private fun myProductsUpdated(action: String, extras: Bundle) = invokeCallbacks(action) {
        extras.getParcelable<MyProductsUpdated>(Events.DATA)!!
    }

I'm not entirely convinced that my handling for reading or writing the list as a parcelable is correct.

At the moment when I try to use this I experience the following crash:

java.lang.RuntimeException: Error receiving broadcast Intent

which is:

Caused by: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: ��9
        at android.os.Parcel.readParcelableCreator(Parcel.java:2556)
        at android.os.Parcel.readParcelable(Parcel.java:2482)
        at com.xx.services.MyProductUpdated$CREATOR.createFromParcel(MyProductsUpdated.kt:26)
        at com.xx.services.events.MyProductsUpdated$CREATOR.createFromParcel(MyProductsUpdated.kt:24)

I believe the issue is to do with the fact that I am writing a 'list' but just reading a parcelable but I'm not quite sure how to resolve that. Any help would be greatly appreciated.


Solution

  • You should be using readList, not readParcelable. Read the contents into an existing list.

    myProducts = mutableListOf<MyProduct>().apply {
        parcel.readList(this, MyProduct::class.java.classLoader)
    }
    

    Also consider using the Parcelize plugin to save yourself some time.