Percelableを実装してIntentに乗せてBundleに渡せるモデルを書く

Percelable interface

モデルをActivity間でやりとりしたり、再生成時の復元処理を書いたり、など、
Percelableというインターフェースを実装すれば、面倒みてくる。
Bundleには基本的な型以外に、Percelableを実装したインスタンスを渡すことができる。
(つまり、ActivityとFragmentに渡すことができる。)
Percelableを実装するとIntentに載せることができる。

Parcelable interfaceは2つの仮想関数を持っていてそれぞれ実装する。
CREATORというstaticメンバを実装する。

  • abstract describeContents()
  • abstract writeToPercel(Percel dest, int flags)
  • CREATOR

abstract describeContents()

describeContents()はひとまず0を返すようにする。
0以外の応答値が必要な場合についてひとまず省略。

abstract writeToPercel(Percel dest, int flags)

writeToPercel(Percel dest, int flags)はPercelに保存するデータを列挙する。
通常クラスが持つプロパティを列挙する。

CREATOR

CREATORという名前のstaticフィールドを実装する必要がある。

Interface for classes whose instances can be written to and restored from a Parcel. Classes implementing the Parcelable interface must also have a non-null static field called CREATOR of a type that implements the Parcelable.Creator interface.

Kotlinはstaticフィールドに対応していない(companionオブジェクトが対応する)ため、
companionオブジェクトとして実装する必要がある。
Percelable.Create<T>というobject式(シングルトンオブジェクト)を継承して作る。

Kotlinから呼ぶだけなら、companionオブジェクトを用意するだけで外からstaticメンバのように扱えるけれども、
Javaから呼ぶなら、さらに@JvmFieldを付ける必要がある。
Kotlnでプロパティを書くと、Javaに変換する際にgetXXX()やsetXXX()のように
自動的にgetter/setterが付く(らしい)。
プロパティに@JvmFieldアノテーションをつけると、getXXX()/setXXX()ではなく、
直接フィールドを触るように変換される。
@JvmFieldを付けずにstaticフィールドを書こうとすると、
勝手にgetXXX()/setXXX()が付いてしまい要求を満たせなくなる。

(JVM言語っぽいところを初めて理解した図…)
実装例は以下参照。

スコープ関数,run

ここ見ながら理解。
任意の型Tの拡張関数で、そのTをレシーバとする関数Rを引数にとる。


public inline fun  T.run(f: T.() -> R): R = f()

例えば、文字列”AIUEO”を小文字にする例。


val str = "AIUEO".run { toLowerCase() }
println(s) //  aiueo

実装例

Kotlinの文法の基本を詰めていれば問題なし。


package com.example.ikuty.myapplication.model

import android.os.Parcel
import android.os.Parcelable

data class Article(val id: String,
                   val title: String,
                   val url: String,
                   val user: User) : Parcelable {
    companion object {
        @JvmField
        val CREATOR: Parcelable.Creator
= object : Parcelable.Creator
{ override fun createFromParcel(source: Parcel): Article = source.run { Article(readString(),readString(),readString(), readParcelable(Article::class.java.classLoader)) } override fun newArray(size: Int): Array = arrayOfNulls(size) } } override fun describeContents(): Int = 0 override fun writeToParcel(dest: Parcel, flags: Int) { dest.run { writeString(id) writeString(title) writeString(url) writeParcelable(user, flags) } } }