Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Serializable / Parcelableとの上手な付き合い方

Serializable / Parcelableとの上手な付き合い方

2025年4月24日(木)開催のpixiv App Nightで発表した資料です。

kobayashi_kento

April 24, 2025
Tweet

More Decks by kobayashi_kento

Other Decks in Technology

Transcript

  1. Serializable 8 Java標準のシリアライズ機構 ※Kotlin Serializationの@Serializableではないです Pros • Serializableと追加するだけなので実装が容易 • Javaの実行環境であれば動作する

    Cons • シリアライズ/デシリアライズの処理速度が 遅い • メモリ消費量が大きい import java.io.Serializable data class Hoge( val fuga: String, val piyo: Int, ) : Serializable
  2. Parcelable 9 AndroidのParcel機構 メモリ上で効率的にデータをやり取りするために設 計されている Pros • シリアライズ/デシリアライズの処理速度が速い • メモリ効率が良い

    Cons • 実装がやや複雑で面倒 • 永続化には向かない import android.os.Parcelable data class Hoge( val fuga: String, val piyo: Int, ) : Parcelable { constructor(parcel: Parcel): this( parcel.readString() ?: "", parcel.readInt(), ) override fun writeToParcel(dest: Parcel?, flags: Int) { if (dst != null) { dest.writeString(fuga) dest.writeInt(piyo) } } override fun describeContents() = 0 companion object CREATOR : Parcelable.Creator<Hoge> { override fun createFromParcel(parcel: Parcel) = Hoge(parcel) override fun newArray(size: Int): Array<Hoge?> = arrayOfNulls(size) } }
  3. Parcelable 10 AndroidのParcel機構 メモリ上で効率的にデータをやり取りするために設 計されている Pros • シリアライズ/デシリアライズの処理速度が速い • メモリ効率が良い

    Cons • 実装がやや複雑で面倒 • 永続化には向かない import android.os.Parcelable import kotlinx.parcelize.Parcelize @Parcelize data class Hoge( val fuga: String, val piyo: Int, ) : Parcelable kotlin-parcelize @Parcelizeで おk
  4. 今後の運用方針 • 新規実装ではParcelableを使用する ◦ @Parcelizeを活用する • 役割を明確にするため、画面遷移に利用するデータはドメインモデルとは別に定義 ◦ 便宜上、ナビゲーションモデルと呼ぶ ◦

    ナビゲーションモデルはnavigationモジュールに配置する ◦ ナビゲーションモデル<-->ドメインモデルの変換ロジックもnavigationモジュールに配置する 17
  5. Listの扱いが型安全 19 • Listの型を指定して型安全に取得可能 • Serializableの場合は自分でキャスト data class Hoge( val

    fuga: String, val piyo: Int, ) : Parcelable // IntentからHogeのArrayListを取得 IntentCompat.getParcelableArrayListExtra( /* in = */ intent, /* key = */ “hoge”, /* clazz = */ Hoge::class.java ) // SerializableはList専用の口がないのでキャストする IntentCompat.getSerializableExtra( /* in = */ data, /* key = */ “hoge”, /* clazz = */ ArrayList::class.java ) as? ArrayList<Hoge>
  6. Serializable vs Parcelable Serizliable • Java • 実装が楽 • 処理速度が遅め

    • メモリ消費大 20 Parcelable • Android固有 • 実装が面倒(プラグインで自動生成が可能) • 処理速度が速め • メモリ消費小
  7. Serializableと比較してParcelableがパフォーマンス優勢な理由 • リフレクションしていない ◦ writeToParcelで明示的に書き出す対象を指定するので解析の手間がなく、実行時の処理が速い • writeString, readString などの専用メソッドにより効率化 ◦

    余計なGCのオーバーヘッドを削減 • Parcelの内部実装で最適化が行われている ◦ メモリマッピングなど • オブジェクトの循環参照を回避している ◦ 循環参照が発生する可能性がある場合、IDを利用して既にデシリアライズされたものを再利用したり、呼 び出された時に参照を解決したりして解決できる 21
  8. モデルの相互変換 22 • それぞれのプロパティに1対1対応す るシンプルな変換 ◦ 遷移元->toNavigationModel ◦ 遷移先->toModel •

    kotlin-fill-classというプラグインを 活用すると効率UP ◦ https://plugins.jetbrains.com/plugin/1094 2-kotlin-fill-class // core/data/model/~/Hoge.kt data class Hoge( val fuga: String, val piyo: Int, ) // core/navigation/~/model/Hoge.kt data class Hoge( val fuga: String, val piyo: Int, ) : Parcelable // core/navigation/~/model/converter/DoM2NaviM.kt fun Hoge.toNavigationModel() = hoge.sample.core.navigation.model.Hoge( fuga = fuga, piyo = piyo, ) // core/navigation/~/model/converter/NaviM2DoM.kt fun Hoge.toModel() = hoge.sample.core.data.model.Hoge( fuga = fuga, piyo = piyo, )
  9. まとめ • ActivityやFragment間のデータ受け渡しはSerializableよりParcelableが優秀 ◦ シリアライズの速度やメモリ効率もParcelableに軍配があがる ◦ ただし、永続化に使うのは避けること • @Parcelizeを活用すべし ◦

    kotlin-parcelizeを導入しよう ◦ ボイラープレートを自動生成してくれて便利 • 役割ごとに型を分けて影響範囲を明確にする ◦ 今回は画面遷移時に引き渡されるパラメータとしてナビゲーションモデルを定義した ◦ ナビゲーションモデルはBundleに格納・取出することに集中する ◦ 遷移先でドメインモデルとして振る舞えるように相互変換を実装する 24