Android Parcelable在Kotlin中:Parcelable数据类上找不到CREATOR

16

随着 Kotlin RC 的发布,我开始编写一个应用程序来学习它,但我无法弄清楚如何让 Parcelable 工作。

数据类:

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)
    }

}

阅读它:

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
    }
}

例外情况:

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)

我相信我错过了一些简单的东西,有没有人在最新的Kotlin上使用Parcelable取得了成功?

Kotlin版本:1.0.0-rc-1036

Kotlin插件版本:1.0.0-rc-1036-IJ143-4

代码可在https://github.com/eggman87/circle-kotlin中查看。

2个回答

28

Kotlin RC现已删除了先前为所有伴生对象属性生成静态字段的过时方式(请在此答案中了解更多信息)。

现在,只有那些标记为constlateinit@JvmField的属性才会生成静态字段。

你需要通过@JvmField注释来注释val CREATOR,因为Android Framework期望在你的类中有一个名为CREATOR的静态字段。


在这种情况下,问题似乎出在获取EXTRA_PROJECT的方式上,只需调用intent.extras.get(EXTRA_PROJECT)即可,但问题不在Parcelable定义中,您不需要添加此内容。 - Juan Saravia
@juancho,我同意,可能以其他方式使用Parcelable不会导致OP中的问题(我甚至无法重现它)。但是异常确实是由于缺少静态字段而抛出的,而答案解决了这个问题。这就是为什么我决定将其还原。你能否复制问题并检查是否解决了它?如果是,我认为这将是更好的答案。 - hotkey
我克隆并测试了这个项目,确实与JvmField有关。我有点困惑为什么在我的项目中没有遇到同样的问题。我也尝试在我的项目中获得相同的错误,但是没有出现。我将删除我的评论以避免混淆。谢谢 :)! - Juan Saravia
同样对于Parcelable实现,@JvmField是不够的,你还需要@Suppress("unused")。在我的情况下,如果没有它,应用程序将无法启动并且仍然会崩溃。 - Tudor
@PopTudor suppress语句只是为了避免编译器警告,不应该对崩溃产生任何影响。 - Eggman87
那个问题现在可能已经解决了吗? - Malachiasz

1

这段代码很可能会因为val CREATOR不再是静态的而在使用Kotlin RC编译时失败。你有检查过吗? - hotkey
我在我的应用程序中使用它与RC。你试过了吗? - Juan Saravia
好的,我会很快检查它。 - hotkey
好的,它可以工作。鉴于此,您能否说明问题中代码的问题在哪里? - hotkey
谢谢您的回答。我已经更新了我的代码,遵循相同的模式,但是在读取时仍然出现BadParcelableException异常。更新后的类:https://github.com/eggman87/circle-kotlin/blob/master/app/src/main/java/com/eggman/circleciandroid/model/Project.kt - Eggman87
@热键 您的回答解决了这个问题 - 感谢提供更多信息的链接。我将其标记为正确的答案。谢谢大家。 - Eggman87

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接