Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
10
Help us understand the problem. What is going on with this article?
@kazhida

KotlinでParcelerを使う話

More than 3 years have passed since last update.

クラスでParcelableを実装するのは、めんどくさいので、JavaではParcelerを使っているのですが、それをKotlinで使おうという話です。

試してみる

まず、

Foo.kt
@Parcel
data class Foo(
        val Hoge: Int,
        val Fuga: String,
        val Piyo: List<String>
)

こんなクラスを考えてみます。

build.gradle
   ・・・
dependencies {
     ・・・
    compile "org.parceler:parceler-api:1.1.1"
    kapt "org.parceler:parceler:1.1.1"
}

こんな風に準備して、いざ、Build。

エラー: Parceler: No @ParcelConstructor annotated constructor and no default empty bean constructor found.

こんな感じのエラーがでます。引数無しのコンストラクタがないですからね。

引数無しのコンストラクタ

Foo.kt
@Parcel
data class Foo(
        val Hoge: Int,
        val Fuga: String,
        val Piyo: List<String>
) {
    private constructor() : this(0, "", ArrayList())
}

としてあげることで、Parcelerを使用できます。
このコンストラクタはprivateにしておいても、Parcelerが生成するクラスではリフレクションで使用できるみたいなので、Parcelerのためだけな場合は、privateにしておくとよいでしょう。

また、問題なければ、

Foo.kt
@Parcel
data class Foo(
        val Hoge: Int = 0,
        val Fuga: String = "",
        val Piyo: List<String> = ArrayList()
)

のように、デフォルト値を指定しておけば、引数無しのコンストラクタも作られるので、それでもかまいません。
ただ、この場合、不要なコンストラクタもできてしまうので、この方法は慎重に使う必要があります。

明示的なコンストラクタの指定

Foo.kt
@Parcel
data class Foo @ParcelConstructor constructor(
        val Hoge: Int,
        val Fuga: String,
        val Piyo: List<String>
)

というように、使用するコンストラクタを指定してあげればできそうな気もするのですが、

エラー: Parceler: No corresponding property found for constructor parameter arg0
エラー: Parceler: No corresponding property found for constructor parameter arg1
エラー: Parceler: No corresponding property found for constructor parameter arg2

というエラーになってしまうので、素直に引数無しのコンストラクタを作ってあげた方が良いようです。

補足

Kotlinのインクリメンタル・コンパイラのせいなのか、kaptがまだまだなのか、はたまた、インスタントランの影響なのかはわかりませんが、ソースを修正しても、build/generated/source/kapt/ に生成されるソースが、そのままになっていることがあります(これで、かなり混乱した)。
意図したようにBuildできないときや、適当なタイミングで、 kaptディレクトリをサクッと削除 して試した方が良いみたいです。

その他の方法

Parcelable code generation( for kotlin's data class) というプラグインもあるので、Parcelerを使わずに、それでParcelableインターフェースのメソッドを生成するという方法もあります。

ただ、

Foo.kt
data class Foo(
        val Hoge: Int,
        val Fuga: String,
        val Piyo: List<String>
) : Parcelable {

    constructor(source: Parcel): this(source.readInt(), source.readString(), source.createStringArrayList())

    override fun describeContents(): Int {
        return 0
    }

    override fun writeToParcel(dest: Parcel?, flags: Int) {
        dest?.writeInt(Hoge)
        dest?.writeString(Fuga)
        dest?.writeStringList(Piyo)
    }

    companion object {
        @JvmField final val CREATOR: Parcelable.Creator<Foo> = object : Parcelable.Creator<Foo> {
            override fun createFromParcel(source: Parcel): Foo {
                return Foo(source)
            }

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

こんな感じになって、すっきりしたdata classの定義が台無しになってしまうので、あまり使いたくないなーと思います。

10
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
10
Help us understand the problem. What is going on with this article?