16

With the release of the Kotlin RC, I started writing an app to learn it however I can not figure out how to get Parcelable to work.

the data class:

data class Project (val reponame:String,
                val username:String,
                val language:String,
                val vcsUrl:String,
                val branches:Map<String, Branch>) : Parcelable {

    companion object {
        val CREATOR = object : Parcelable.Creator<Project> {
            override fun createFromParcel(`in`: Parcel): Project {
                return Project(`in`)
            }

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

    protected constructor(parcelIn: Parcel) : this (
            parcelIn.readString(),
            parcelIn.readString(),
            parcelIn.readString(),
            parcelIn.readString(),
            mapOf<String, Branch>().apply {
                parcelIn.readMap(this, Branch::class.java.classLoader)
            }
    )

    override fun describeContents(): Int {
        throw UnsupportedOperationException()
    }

    override fun writeToParcel(dest: Parcel, flags: Int) {
        dest.writeString(reponame)
        dest.writeString(username)
        dest.writeString(language)
        dest.writeString(vcsUrl)
        dest.writeMap(branches)
    }

}

Reading it:

class ProjectDetailActivity : BaseActivity() {

    lateinit var project: Project

    companion object {
        const val EXTRA_PROJECT = "extra_project"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        project = intent.extras.getParcelable(EXTRA_PROJECT)

        tvTitle.text = project.reponame
    }
}

The exception:

Caused by: android.os.BadParcelableException: Parcelable protocol requires a Parcelable.Creator object called CREATOR on class com.eggman.circleciandroid.model.Project
    at android.os.Parcel.readParcelableCreator(Parcel.java:2415)
    at android.os.Parcel.readParcelable(Parcel.java:2337)
    at android.os.Parcel.readValue(Parcel.java:2243)
    at android.os.Parcel.readArrayMapInternal(Parcel.java:2592)
    at android.os.BaseBundle.unparcel(BaseBundle.java:221)
    at android.os.BaseBundle.get(BaseBundle.java:281)
    at com.eggman.circleciandroid.ui.ProjectDetailActivity.onCreate(ProjectDetailActivity.kt:22)

I am sure it is something simple I am missing, has anyone else had success with Parcelable on latest Kotlin?

Kotlin Version: 1.0.0-rc-1036

Kotlin Plugin Version: 1.0.0-rc-1036-IJ143-4

Code is viewable @ https://github.com/eggman87/circle-kotlin

hotkey
  • 140,743
  • 39
  • 371
  • 326
Eggman87
  • 571
  • 5
  • 12

2 Answers2

28

Kotlin RC dropped previously deprecated generation of static fields for all companion object properties (learn more in this answer).

Now only those marked by const, lateinit or @JvmField will have a static field generated.

You need to annotate val CREATOR by @JvmField annotation since Android Framework expects a static field CREATOR in your class.

Community
  • 1
  • 1
hotkey
  • 140,743
  • 39
  • 371
  • 326
  • In this case the problem seems to be in the way you are getting the *EXTRA_PROJECT*, just call intent.extras.get(EXTRA_PROJECT) but the problem is not in the Parcelable definition, you don't need to add this. – Juan Saravia Feb 08 '16 at 15:12
  • @juancho, I agree that, possibly, some other way of working with `Parcelable` wouldn't cause the problem in OP (and I could not even reproduce it). But the exception there is definitely thrown because of the missing static field, and the answer resolves it. That's why I decided to undelete it. Could you please reproduce the problem and check if this solves it? If it does, I think, it would be a better answer. – hotkey Feb 08 '16 at 15:23
  • I clone and test the project and yes it's regarding this JvmField. I'm a little confuse why I'm not facing the same issue in my project. Also I tried to get the same error in my project but nothing. I'll delete my comments just to avoid confusions. Thanks :) ! – Juan Saravia Feb 08 '16 at 16:11
  • also for parcelable implementation, @JvmField is not enough, you also need @Suppress("unused"). In my case it wouldn't start without it and I would still had the crash – Tudor Feb 11 '16 at 10:51
  • @PopTudor the suppress statement is only to avoid compiler warnings, should not have any impact on a crash. – Eggman87 Feb 11 '16 at 15:53
  • Is that perhaps fixed meanwhile? – Malachiasz Apr 03 '20 at 04:45
1

Here you have some useful Kotlin extension functions that will help you to create your CREATORs and also some examples (using data classes and list inside the data class)

Gist: Data Class & Parcelables example

I'm using this code in an Android App: (link)

The same code you can find it here: (link)

hotkey
  • 140,743
  • 39
  • 371
  • 326
Juan Saravia
  • 7,661
  • 6
  • 29
  • 41
  • This code most probably will fail for the same reason if compiled with Kotlin RC (because of `val CREATOR` not being static anymore). Did you check it? – hotkey Feb 07 '16 at 14:20
  • I'm using it in my app with the RC. Did you tried it? – Juan Saravia Feb 07 '16 at 14:21
  • Ok, I'll check it shortly. – hotkey Feb 07 '16 at 14:26
  • Well, it works. Given that, can you state what's wrong in code in the question? – hotkey Feb 07 '16 at 15:03
  • Thanks for the answer. I updated my code to follow the same pattern but I am still getting the BadParcelableException when reading. Updated class: https://github.com/eggman87/circle-kotlin/blob/master/app/src/main/java/com/eggman/circleciandroid/model/Project.kt – Eggman87 Feb 07 '16 at 16:42
  • @hotkey your answer resolves the issue - thanks for the link with more info. Marked it as correct. Thanks everyone. – Eggman87 Feb 07 '16 at 17:18