趣旨
前回の記事でsealedを使った代数データ(直和)型を書きました。
Android開発においてActivity間などアプリ内で情報を流通させるのにデータクラスをParcelableに
しておくと何かと都合が良いですが、sealedを使ったクラスをParcelableにします。
もう少し具体的に書くと、もともとParcelableだったクラス(前回の記事でいうと、PBookとEBookクラス)を統合して代数データ型のクラス(前回の記事のBookクラス)にして、その統合クラス自体もParcelbleにするというのが今回の記事です。
もともとParcelableは、冗長でテンプレ的な側面を持っており、Parcelableを簡素に記述するためのライブラリなどもありますが、それは次回の予定記事としたいと思います。
今回は、まずは実直にParcelableを実装してみます。
前回の復習と今回の概要
一旦、復習代わりにもう一度背景を書きます。
data class PBook(var id : Long, var name : String, var kakaku : Int)
data class EBook(var id : Long, var name : String, var kakaku : Int)
の既存クラスに手を入れずにBookクラスとして統合して扱うために、
sealed class Book {
class PBOOK(val pBook : PBook) : Book()
class EBOOK(val eBook : EBook) : Book()
}
としました。ちなみに、前回の記事ではBookクラスにはtitle, priceプロパティやunwrapメソッドを書いてましたが、今回のParcelable化の記事では焦点がぼやけるため省略しています。
今回の記事の肝
前回はAndroid開発に限らないKotlin言語の記事として書いたため既存クラスをParcelableでないものとして記述していましたが、記事の元ネタとなった実際のAndroid開発ではParcelableだったのでした。
つまり、
data class PBook(var id : Long, var name : String, var kakaku : Int)
data class EBook(var id : Long, var name : String, var kakaku : Int)
ではなくて、
data class PBook(var id : Long, var name : String, var kakaku : Int) : Parcelable { ...省略... }
data class EBook(var id : Long, var name : String, var kakaku : Int) : Parcelable { ...省略... }
でした。
このとき、前回の記事で統合したBookクラスもParcelableにして、
sealed class Book : Parcelable {
class PBOOK(val pBook : PBook) : Book()
class EBOOK(val eBook : EBook) : Book()
}
のようにしたいのですが、Parcelableを、どう実装することになるのでしょうか?というのが本記事の趣旨です。
ちなみに、PBookを例にとってParcelbleの実装をきちんと記述すると
data class PBook(var id : Long,
var name : String,
var kakaku : Int) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readLong(),
parcel.readString(),
parcel.readInt())
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeLong(id)
parcel.writeString(name)
parcel.writeInt(kakaku)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<PBook> {
override fun createFromParcel(parcel: Parcel): PBook {
return PBook(parcel)
}
override fun newArray(size: Int): Array<PBook?> {
return arrayOfNulls(size)
}
}
}
のようになります。面倒ですね、Parcelable。
結論
さて、BookクラスをParcelableにするには以下のようにします。
sealed class Book : Parcelable {
class PBOOK(var pBook : PBook): Book() {
constructor(parcel: Parcel) : this(parcel.readParcelable<PBook>(PBook::class.java.classLoader))
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeParcelable(pBook, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<PBOOK> {
override fun createFromParcel(parcel: Parcel): PBOOK {
return PBOOK(parcel)
}
override fun newArray(size: Int): Array<PBOOK?> {
return arrayOfNulls(size)
}
}
}
class EBOOK(var eBook : EBook) : Book() {
constructor(parcel: Parcel) : this(parcel.readParcelable<EBook>(EBook::class.java.classLoader))
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeParcelable(eBook, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<EBOOK> {
override fun createFromParcel(parcel: Parcel): EBOOK {
return EBOOK(parcel)
}
override fun newArray(size: Int): Array<EBOOK?> {
return arrayOfNulls(size)
}
}
}
}
Bookクラスは、抽象クラスになるので、Parcelableを実装するのは、具象クラスのBook.PBOOKとBook.EBOOKクラスということになります。
ぼんやりと眺めるとPBookとEBookクラスのParcelbleの実装をしているように見えますが、あくまでもラッパー側のBook.PBOOKとBook.EBOOKの実装をしています。
これで、BookクラスもParcelableになり、Androidの中でActivityやFrafmentを越えて書籍情報を流通させることができるようになりました。
しかし、なんて面倒臭いのでしょう。ここでPaperParcelを導入するともっと楽に記述できるのですが。。。。
つづく
ということで、次はParparParcelを導入してsealedクラスをParcelabeにしてみたいと思います。
特にインナークラスの実装がPaperParcelでは、どうなるかが肝となります。