2017年7月13日木曜日

Kotlin メモ : Parcelable

Java
  1. public class Receipt implements Parcelable {  
  2.   
  3.     @NonNull  
  4.     private final Date date;  
  5.     private final int value;  
  6.   
  7.     public Receipt(@NonNull Date date, int value) {  
  8.         this.date = date;  
  9.         this.value = value;  
  10.     }  
  11.   
  12.     @NonNull  
  13.     public Date getDate() {  
  14.         return date;  
  15.     }  
  16.   
  17.     public int getValue() {  
  18.         return value;  
  19.     }  
  20.   
  21.     @Override  
  22.     public boolean equals(Object o) {  
  23.         if (this == o) return true;  
  24.         if (o == null || getClass() != o.getClass()) return false;  
  25.   
  26.         Receipt receipt = (Receipt) o;  
  27.   
  28.         if (value != receipt.value) return false;  
  29.         return date.equals(receipt.date);  
  30.     }  
  31.   
  32.     @Override  
  33.     public int hashCode() {  
  34.         int result = date.hashCode();  
  35.         result = 31 * result + value;  
  36.         return result;  
  37.     }  
  38.   
  39.     //  
  40.     // Parcelable  
  41.     //  
  42.   
  43.     @Override  
  44.     public int describeContents() {  
  45.         return 0;  
  46.     }  
  47.   
  48.     @Override  
  49.     public void writeToParcel(Parcel dest, int flags) {  
  50.         dest.writeSerializable(date);  
  51.         dest.writeInt(value);  
  52.     }  
  53.   
  54.     public static final Creator<Receipt> CREATOR = new Creator<Receipt>() {  
  55.         @Override  
  56.         public Receipt createFromParcel(Parcel in) {  
  57.             return new Receipt((Date) in.readSerializable(), in.readInt());  
  58.         }  
  59.   
  60.         @Override  
  61.         public Receipt[] newArray(int size) {  
  62.             return new Receipt[size];  
  63.         }  
  64.     };  
  65. }  
Kotlin 自動変換直後
  1. class Receipt(val date: Date, val value: Int) : Parcelable {  
  2.   
  3.     override fun equals(o: Any?): Boolean {  
  4.         if (this === o) return true  
  5.         if (o == null || javaClass != o.javaClass) return false  
  6.   
  7.         val receipt = o as Receipt?  
  8.   
  9.         if (value != receipt!!.value) return false  
  10.         return date == receipt.date  
  11.     }  
  12.   
  13.     override fun hashCode(): Int {  
  14.         var result = date.hashCode()  
  15.         result = 31 * result + value  
  16.         return result  
  17.     }  
  18.   
  19.     //  
  20.     // Parcelable  
  21.     //  
  22.   
  23.     override fun describeContents(): Int {  
  24.         return 0  
  25.     }  
  26.   
  27.     override fun writeToParcel(dest: Parcel, flags: Int) {  
  28.         dest.writeSerializable(date)  
  29.         dest.writeInt(value)  
  30.     }  
  31.   
  32.     companion object {  
  33.   
  34.         val CREATOR: Parcelable.Creator<Receipt> = object : Parcelable.Creator<Receipt> {  
  35.             override fun createFromParcel(`in`: Parcel): Receipt {  
  36.                 return Receipt(`in`.readSerializable() as Date, `in`.readInt())  
  37.             }  
  38.   
  39.             override fun newArray(size: Int): Array<Receipt> {  
  40.                 return arrayOfNulls(size)  
  41.             }  
  42.         }  
  43.     }  
  44. }  
return arrayOfNulls(size) で型があわないと言われるので、newArray() の返す型を Array<Receipt?> にする

  1. override fun newArray(size: Int): Array<receipt?> {  
  2.      return arrayOfNulls(size)  
  3.  }  
CREATOR が Java から見えるように @JvmField をつける
  1. companion object {  
  2.     @JvmField  
  3.     val CREATOR: Parcelable.Creator<Receipt> = object : Parcelable.Creator<Receipt> {  



(Parcelable とは関係ないが) data クラスにして equals() と hashCode() を省略する
  1. data class Receipt(val date: Date, val value: Int) : Parcelable {  
  2.   
  3.     override fun describeContents(): Int {  
  4.         return 0  
  5.     }  
  6.   
  7.     override fun writeToParcel(dest: Parcel, flags: Int) {  
  8.         dest.writeSerializable(date)  
  9.         dest.writeInt(value)  
  10.     }  
  11.   
  12.     companion object {  
  13.         @JvmField  
  14.         val CREATOR: Parcelable.Creator<Receipt> = object : Parcelable.Creator<Receipt> {  
  15.             override fun createFromParcel(`in`: Parcel): Receipt {  
  16.                 return Receipt(`in`.readSerializable() as Date, `in`.readInt())  
  17.             }  
  18.   
  19.             override fun newArray(size: Int): Array<Receipt?> {  
  20.                 return arrayOfNulls(size)  
  21.             }  
  22.         }  
  23.     }  
  24. }  
describeContents() と newArray() で = を使って関数の本体を省略
  1. data class Receipt(val date: Date, val value: Int) : Parcelable {  
  2.   
  3.     override fun describeContents() = 0  
  4.   
  5.     override fun writeToParcel(dest: Parcel, flags: Int) {  
  6.         dest.writeSerializable(date)  
  7.         dest.writeInt(value)  
  8.     }  
  9.   
  10.     companion object {  
  11.         @JvmField  
  12.         val CREATOR: Parcelable.Creator<Receipt> = object : Parcelable.Creator<Receipt> {  
  13.             override fun createFromParcel(`in`: Parcel): Receipt {  
  14.                 return Receipt(`in`.readSerializable() as Date, `in`.readInt())  
  15.             }  
  16.   
  17.             override fun newArray(size: Int): Array<Receipt?> = arrayOfNulls(size)  
  18.         }  
  19.     }  
  20. }  
createFromParcel() の引数名に Java では in が使われているが、 Kotlin では予約語なので ` でエスケープされている。
紛らわしいので source に変える
  1. data class Receipt(val date: Date, val value: Int) : Parcelable {  
  2.   
  3.     override fun describeContents() = 0  
  4.   
  5.     override fun writeToParcel(dest: Parcel, flags: Int) {  
  6.         dest.writeSerializable(date)  
  7.         dest.writeInt(value)  
  8.     }  
  9.   
  10.     companion object {  
  11.         @JvmField  
  12.         val CREATOR: Parcelable.Creator<Receipt> = object : Parcelable.Creator<Receipt> {  
  13.             override fun createFromParcel(source: Parcel): Receipt {  
  14.                 return Receipt(source.readSerializable() as Date, source.readInt())  
  15.             }  
  16.   
  17.             override fun newArray(size: Int): Array<Receipt?> = arrayOfNulls(size)  
  18.         }  
  19.     }  
  20. }  
writeToParcel() の dest と createFromParcel() の source でスコープ関数を使う(お好みで)
  1. data class Receipt(val date: Date, val value: Int) : Parcelable {  
  2.   
  3.     override fun describeContents() = 0  
  4.   
  5.     override fun writeToParcel(dest: Parcel, flags: Int) {  
  6.         dest.run {  
  7.             writeSerializable(date)  
  8.             writeInt(value)  
  9.         }  
  10.     }  
  11.   
  12.     companion object {  
  13.         @JvmField  
  14.         val CREATOR: Parcelable.Creator<Receipt> = object : Parcelable.Creator<Receipt> {  
  15.             override fun createFromParcel(source: Parcel): Receipt  
  16.                     = source.run { Receipt(readSerializable() as Date, readInt()) }  
  17.   
  18.             override fun newArray(size: Int): Array<Receipt?> = arrayOfNulls(size)  
  19.         }  
  20.     }  
  21. }  
run() を使っています。
他のスコープ関数(let, with, run, apply, also)を使うと次のようになります。

writeToParcel() ではどれを使ってもやりたいことはできます。
選ぶとしたら it が省略できる(そのレシーバを this とする関数を呼び出す) with か run か apply がよさそうです。
  1. // let  
  2. dest.let {  
  3.     it.writeSerializable(date)  
  4.     it.writeInt(value)  
  5. }  
  6.   
  7. // with  
  8. with(dest) {  
  9.     writeSerializable(date)  
  10.     writeInt(value)  
  11. }  
  12.   
  13. // run  
  14. dest.run {  
  15.     writeSerializable(date)  
  16.     writeInt(value)  
  17. }  
  18.   
  19. // apply  
  20. dest.apply {  
  21.     writeSerializable(date)  
  22.     writeInt(value)  
  23. }  
  24.   
  25. // also  
  26. dest.also {  
  27.     it.writeSerializable(date)  
  28.     it.writeInt(value)  
  29. }  
createFromParcel() では、レシーバーの Parcel ではなく Receipt を返したいので apply, also は使えません。
ここでも選ぶとしたら it が省略できる with か run がよさそうです。
  1. // let  
  2. override fun createFromParcel(source: Parcel): Receipt  
  3.         = source.let { Receipt(it.readSerializable() as Date, it.readInt()) }  
  4.   
  5. // with  
  6. override fun createFromParcel(source: Parcel): Receipt  
  7.         = with(source) { Receipt(readSerializable() as Date, readInt()) }  
  8.   
  9. // run  
  10. override fun createFromParcel(source: Parcel): Receipt  
  11.         = source.run { Receipt(readSerializable() as Date, readInt()) }  
65行が21行になった。



0 件のコメント:

コメントを投稿