首页 > 解决方案 > “Parcelable 协议需要一个名为 CREATOR 的 Parcelable.Creator 对象”(我确实有 CREATOR) - 在 Kotlin 中

问题描述

我收到错误消息“Parcelable 协议需要一个名为 CREATOR 的 Parcelable.Creator 对象在类......”,但我确实有一个 Creator,但我不知道它有什么问题。我从https://developer.android.com/reference/android/os/Parcelable复制了它并更改了类名以适合我的代码。我怀疑从 Java 到 Kotlin 的(自动)转换并不完美(或者准确地说:它是否与需要的略有不同),但我不知道问题到底是什么。

有一个带有相同错误消息的线程(Parcelable 协议需要一个名为 CREATOR 的 Parcelable.Creator 对象(我确实有 CREATOR))但问题是“有趣的 writeToParcel”没有按照读取的顺序写入“有趣的数据处理程序”。就我而言,这不是问题,因为它的顺序相同。

那里的另一个答案指出,函数需要是静态的可能是个问题。但是,Kotlin 没有“静态”功能。我读到它是用“伴侣对象”完成的。我试过了(见下文),但它引发了另一个错误 - 我不确定它是否会起作用。

class DataHandler : Parcelable {

    var player1name = ""
    var player1color = 0

    //main constructor
    fun DataHandler(player1name: String, player1color: Int) {
        this.player1name = player1name
        this.player1color = player1color
    }


    //write object values to parcel for storage
    override fun writeToParcel(dest: Parcel, flags: Int) {
        //write all properties to the parcle
        dest.writeString(player1name)
        dest.writeInt(player1color)
    }

    //constructor used for parcel
    fun DataHandler(parcel: Parcel) {
        //read and set saved values from parcel
        player1name = parcel.readString()
        player1color = parcel.readInt()
    }

    //creator - used when un-parceling our parcle (creating the object)
    val CREATOR: Parcelable.Creator<DataHandler> = object : Parcelable.Creator<DataHandler> {

        override fun createFromParcel(parcel: Parcel): DataHandler {
            return DataHandler(parcel) as DataHandler
        }

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

    //return hashcode of object
    override fun describeContents(): Int {
        return hashCode()
    }
}

这是发送活动:

        val intentPickPlayer = Intent(this, PlayGame::class.java)

        var dataHandler = DataHandler()
        dataHandler.player1name = "testing"
        intentPickPlayer.putExtra("data", dataHandler)

        startActivity(intentPickPlayer)

这是接收活动:

class PlayGame : Activity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.playgame)

    val test = intent.getParcelableExtra<DataHandler>("data")

    Toast.makeText(this, test.player1name, Toast.LENGTH_SHORT).show()

}

如上所述:我试图通过将 CREATOR 放入伴随对象中来使其成为静态(显然这是它在 Kotlin 中的工作方式,但这会产生另一个错误(我不确定它是否解决了第一个问题)

companion object {
//creator - used when un-parceling our parcle (creating the object)
val CREATOR: Parcelable.Creator<DataHandler> = object : Parcelable.Creator<DataHandler> {

    override fun createFromParcel(parcel: Parcel): DataHandler {
        //HERE COMES AN ERROR: parcel has a red underlining and it says: "too many Arguments for public constructor DataHandler()
        return DataHandler(parcel) as DataHandler
    }

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

标签: androidkotlinparcelableparcelcompanion-object

解决方案


在 Kotlin 中,构造函数由constructor关键字定义 - https://kotlinlang.org/docs/reference/classes.html

有关辅助构造函数的信息,另请参阅https://kotlinlang.org/docs/reference/classes.html#secondary-constructors。辅助构造函数需要委托给主构造函数。

默认构造函数通常在定义为它的一部分的类名和属性之后定义:

类 DataHandler(var player1name: String, var player1color: Int) : Parcelable {

     //将对象值写入parcel进行存储
    覆盖有趣的 writeToParcel(dest: Parcel, flags: Int) {
        //将所有属性写入parcle
        dest.writeString(player1name)
        dest.writeInt(player1color)
    }

    //用于包裹的构造函数
    构造函数(包裹:包裹):这个(
        //从包裹中读取并设置保存的值
        player1name = parcel.readString(),
        player1color = parcel.readInt())

    伴随对象{
        @JvmField
        //creator - 在解包我们的包裹时使用(创建对象)
        val 创建者:Parcelable.Creator = 对象:Parcelable.Creator {

            覆盖乐趣 createFromParcel(parcel: Parcel): DataHandler {
                返回 DataHandler(parcel) 作为 DataHandler
            }

            覆盖有趣的 newArray(size: Int): Array {
                返回arrayOfNulls(大小)
            }
        }
    }

    //返回对象的hashcode
    覆盖有趣的 describeContents(): Int {
        返回哈希码()
    }
}


推荐阅读