以下のようにすることで実装してくことができます。
ポイントはsealed class自体にはParcelizeをつけないで、サブクラスで実装させることです。
sealed class Sealed(open val sealedClassProperty: String) : Parcelable {
@Parcelize
data class SubDataClass(val subClassProperty: String, override val sealedClassProperty: String) : Sealed(sealedClassProperty)
@Parcelize
class SubClass(val subClassProperty: String, override val sealedClassProperty: String) : Sealed(sealedClassProperty)
@Parcelize
object SubObject : Sealed("test") {
val objStr: String = "test"
}
}
}
確認コード
val p = Parcel.obtain()
val bundle = Bundle()
val subDataClass = Sealed.SubDataClass("a", "b")
bundle.putParcelable("SubDataClass", subDataClass)
val subClass = Sealed.SubClass("a", "b")
bundle.putParcelable("SubClass", subClass)
val subObject = Sealed.SubObject
bundle.putParcelable("SubObject", subObject)
p.writeBundle(bundle)
p.setDataPosition(0)
val restoredBundle = p.readBundle(Sealed::class.java.classLoader)
println(restoredBundle!!.getParcelable<Sealed>("SubDataClass"))
println(restoredBundle.getParcelable<Sealed>("SubClass"))
println(restoredBundle.getParcelable<Sealed>("SubObject"))
p.recycle()
}
実行結果
I/System.out: SubDataClass(subClassProperty=a, sealedClassProperty=b)
I/System.out: com.github.takahirom.sealedparcelable.MainActivity$Sealed$SubClass@3a66f1d
I/System.out: com.github.takahirom.sealedparcelable.MainActivity$Sealed$SubObject@1265592
CREATORを指定しなくてなぜうまく動くのか?
デコンパイルしてみて見るとParcelizeはCREATORなどを自動生成してくれるようです。
しかし以下のコードでは親クラスでgetParcelableを呼ぶだけで、サブクラスのCREATORを指定していません。
println(restoredBundle!!.getParcelable<Sealed>("SubDataClass"))
なぜCREATORを指定しなくてなぜうまく動くのでしょうか?
Parcelは以下のようなバイト列を持っています。
以下のようにすることで見ることができます。
p.setDataPosition(0)
File(dataDir, "parcelable").outputStream().write(p.createByteArray())
まずここから4というのを取り出してこれがParcelableだということを取得し、
またその後にクラス名を取得し、
そこからCREATORクラスを取得します。
このようにParcelの中に保存するときにクラス名が入るため、取得するときにシールドクラスの親クラスを指定していても、うまくCREATORを使ってくれて動くようです。