KotlinのParcelizeについて

採用はこちら

@Parcelize は、Android × Kotlin 開発において Parcelable 実装を現実的なコストで扱うための必須機能です。

一方で、使い方を誤ると TransactionTooLargeException や設計崩壊の原因にもなります。

本記事では、

  • Parcelizeの正確な役割
  • Parcelableとの関係
  • 現行API(Android 13 / API 33以降)を踏まえた正しい使い方
  • 実務で事故らない設計指針

までを断定しすぎない・古くならない表現で整理します。

目次

@Parcelizeとは何か

@Parcelize は、Kotlinコンパイラによって Parcelable 実装を自動生成する仕組みです。

本来、Parcelable を手書きすると以下が必要になります。

  • writeToParcel()
  • describeContents()
  • CREATOR の実装
  • 読み書き順序の厳密管理

@Parcelize を使うと、これらを 宣言的に省略できます。

@Parcelize
data class User(
    val id: Int,
    val name: String
) : Parcelable

実装量を減らしつつ、Androidに最適化された高速なデータ受け渡しを実現できます。

ParcelableがAndroidで使われる理由

Androidでは、以下のような場面でオブジェクトの受け渡しが頻発します。

  • Activity ↔ Activity
  • Fragment ↔ Fragment
  • Service ↔ Activity
  • Intent / Bundle 経由の状態共有

この用途のために用意されているのが Parcelable です。

Serializableとの比較(実務視点)

観点ParcelableSerializable
Android最適化
実行速度高速遅め
実装コスト高い(通常)低い
@Parcelize使用時低い
実務での推奨基本はこちら例外的

SerializableはJava標準で手軽ですが、AndroidではParcelableが基本方針と考えるのが安全です。

Parcelizeを使うための設定

Gradle設定(必須)

plugins {
    id("kotlin-parcelize")
}
  • kotlin-android-extensions非推奨
  • Kotlin DSLの場合は kotlin("parcelize") でも可

Intent / Bundleでの受け渡し(現行API準拠)

送る側

intent.putExtra("user", user)

受け取る側(API 33以降 推奨)

val user = intent.getParcelableExtra("user", User::class.java)

Fragmentの場合:

val user = arguments?.getParcelable("user", User::class.java)

※ 古い getParcelableExtra<T>(key) 形式はAPI 33以降では 非推奨(deprecated)扱いになるため注意が必要です。

Parcelizeで扱える型の考え方

Parcelizeは「型名」ではなく、Parcelに安全に書き込めるかどうかで可否が決まります。

問題なく使えるもの

  • プリミティブ型(Int, Long, Boolean 等)
  • String
  • Enum
  • Parcelableを実装したクラス

コレクション

List<T>
ArrayList<T>

T が Parcelable / プリミティブ等である必要あり

Mapについての注意

Map<String, T>
  • 動作するケースはある
  • しかし 型消去・可読性・保守性の観点でハマりやすい
  • 実務では DTO に分解する方が安全

Nullable・デフォルト値

@Parcelize
data class Profile(
    val name: String?,
    val age: Int = 0
) : Parcelable
  • Nullable → 問題なし
  • デフォルト値 → 問題なし

enum / sealed class の扱い

enum

enum class Status { ACTIVE, INACTIVE }

問題なく Parcelize 可能です。

sealed class(重要)

@Parcelize
sealed class UiState : Parcelable {

    @Parcelize
    data class Success(val data: String) : UiState()

    @Parcelize
    data class Error(val message: String) : UiState()
}
  • sealed class本体 + 各サブクラスに @Parcelize が必要
  • object 型のサブクラスも同様

Parcelizeの仕組みとパフォーマンス

  • Parcelizeは コンパイル時コード生成
  • Serializableのようなリフレクションは使用しない
  • データを順序固定のバイナリ形式で書き込む

そのため、一般に Parcelable + Parcelize の方が高速です。
(※ 実際の速度差はデータ量・端末条件に依存)

よくある落とし穴

巨大データを渡す

  • Intent / Bundle 経由のデータは
    Binderトランザクション制限により TransactionTooLargeException が発生することがあります
  • 実務上は「1MB前後で危険」と考えるのが一般的

✅ 対策

  • IDやキーのみ渡す
  • 実データは Repository / DB / キャッシュ経由で取得

Context / View を含める

val context: Context // ❌
  • ライフサイクル問題
  • 設計上もNG

Bitmapについて

  • Bitmap は Parcelable を実装している
  • 技術的には渡せる
  • しかしサイズが大きくなりやすく、例外の原因になりがち

実務では URI / ファイルパス / キャッシュキーを渡すのが基本

@IgnoredOnParcel

@IgnoredOnParcel
val tempCache: String? = null
  • Parcel化対象から除外できる
  • 一時データ・計算結果向け

ただし、そもそも渡すモデルに含めない設計の方が健全なケースも多いです。

Serializableとの付き合い方(現実解)

  • Androidでは 基本はParcelable
  • Serializableは以下のような場合に限定して使われることがある
    • 既存資産との互換
    • 一時的な実装
    • 非Android層との共通モデル

「Parcelize一択」と言い切るより、「原則Parcelable、例外的にSerializable」が正確です。

実務ベストプラクティスまとめ

  • 画面遷移専用のDTOに Parcelize を使う
  • DB Entity / Domain Model を直接 Parcelable にしない
  • 大きなデータは渡さない
  • UI State(sealed class)との相性は良い
  • API 33以降の取得方法に注意

まとめ

@Parcelize は、Parcelableを「使えるもの」に変えた重要機能です。

ただし 便利さに任せて何でも詰め込むと事故るのも事実。

  • 軽量
  • 明確な責務
  • 画面遷移専用

この3点を守れば、Parcelizeは Android開発における最強クラスの武器になります。

以上、KotlinのParcelizeについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次