Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Serializable / Parcelableとの上手な付き合い方
Search
kobaken
April 24, 2025
Technology
0
65
Serializable / Parcelableとの上手な付き合い方
2025年4月24日(木)開催のpixiv App Nightで発表した資料です。
kobaken
April 24, 2025
Tweet
Share
More Decks by kobaken
See All by kobaken
Jetpack Compose Preview実践ガイド
kobaken0029
0
85
Kotlinの好きなところ
kobaken0029
0
1.1k
Compose駆動開発のためのマルチモジュール化
kobaken0029
0
220
DataStoreを導入してみた
kobaken0029
1
330
Epoxyを用いたレイアウト構築術
kobaken0029
1
230
Androidエンジニアが1週間でiOSアプリ開発を学び、1ヶ月で大規模アプリ開発にJOINした話
kobaken0029
0
3.3k
Modern REST Communicate for Android
kobaken0029
0
1.5k
AndroidでモダンREST通信してみたった
kobaken0029
0
250
Other Decks in Technology
See All in Technology
Observability — Extending Into Incident Response
nari_ex
1
330
AI機能プロジェクト炎上の 3つのしくじりと学び
nakawai
0
110
現場データから見える、開発生産性の変化コード生成AI導入・運用のリアル〜 / Changes in Development Productivity and Operational Challenges Following the Introduction of Code Generation AI
nttcom
1
480
Open Table Format (OTF) が必要になった背景とその機能 (2025.10.28)
simosako
2
200
GraphRAG グラフDBを使ったLLM生成(自作漫画DBを用いた具体例を用いて)
seaturt1e
1
150
OTEPsで知るOpenTelemetryの未来 / Observability Conference Tokyo 2025
arthur1
0
250
AI時代におけるデータの重要性 ~データマネジメントの第一歩~
ryoichi_ota
0
710
デザインとエンジニアリングの架け橋を目指す OPTiMのデザインシステム「nucleus」の軌跡と広げ方
optim
0
120
組織全員で向き合うAI Readyなデータ利活用
gappy50
1
350
FinOps について (ちょっと) 本気出して考えてみた
skmkzyk
0
210
AI-Readyを目指した非構造化データのメダリオンアーキテクチャ
r_miura
1
320
Kubernetes self-healing of your workload
hwchiu
0
540
Featured
See All Featured
Stop Working from a Prison Cell
hatefulcrawdad
272
21k
GraphQLの誤解/rethinking-graphql
sonatard
73
11k
Making the Leap to Tech Lead
cromwellryan
135
9.6k
How To Stay Up To Date on Web Technology
chriscoyier
791
250k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1k
The Art of Programming - Codeland 2020
erikaheidi
56
14k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.5k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
140
34k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
130k
Designing Experiences People Love
moore
142
24k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
37
2.6k
Transcript
Serializable / Parcelableとの 上手な付き合い方 @kobaken
Index • Serializable / Parcelableとは • pixivコミックで問題になった事象 • なぜ発生してしまったのか •
今後の運用方針 • まとめ 2
Serializable / Parcelable 3
4 https://developer.android.com/develop/ui/views/touch-and-input/stylus-input/ink-api-state-preservation
5 https://developer.android.com/develop/ui/views/touch-and-input/stylus-input/ink-api-state-preservation
6 🤔💭
Serializable / Parcelableとは • オブジェクトを直列化するためのinterface ◦ オブジェクトをバイト列に変換(シリアライズ)、復元(デシリアライズ)する処理 • ActivityやFragment, Serviceなどのコンポーネント間のデータ受け渡し(画面遷移
など)や永続化などの際に利用されることが多い 7
Serializable 8 Java標準のシリアライズ機構 ※Kotlin Serializationの@Serializableではないです Pros • Serializableと追加するだけなので実装が容易 • Javaの実行環境であれば動作する
Cons • シリアライズ/デシリアライズの処理速度が 遅い • メモリ消費量が大きい import java.io.Serializable data class Hoge( val fuga: String, val piyo: Int, ) : Serializable
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) } }
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
問題になった事象 11
前提 • pixivコミック Androidアプリでは画面遷移をActivity.startActivityで行っている • マルチモジュール化を進行中 ◦ 大半の実装がappモジュール内にまとまったままになっている 12
問題になった事象 • 画面遷移時にBundleからデータを取得する箇所でクラッシュが発生💣💥 13
問題になった事象 • 画面遷移時にBundleからデータを取得する箇所でクラッシュが発生💣💥 解決策 • Serializableにロールバックした ◦ 早急な対応のため、手数が少なく、動作の実績がある元実装に戻した 14
なぜ発生したのか • 対応するclassをSerializable->Parcelableに置き換えていたが、Bundleから取り出 す処理をSerializable時代のままにしていた • pixivコミック Androidチームでは変更箇所の動作確認をリリース前に行なっている • 当時改修対象だった機能の動作も問題なかった ◦
影響範囲の調査不足(影響範囲が広い実装の変更だった) 15
今後の運用方針 16
今後の運用方針 • 新規実装ではParcelableを使用する ◦ @Parcelizeを活用する • 役割を明確にするため、画面遷移に利用するデータはドメインモデルとは別に定義 ◦ 便宜上、ナビゲーションモデルと呼ぶ ◦
ナビゲーションモデルはnavigationモジュールに配置する ◦ ナビゲーションモデル<-->ドメインモデルの変換ロジックもnavigationモジュールに配置する 17
Parcelableに変えていく理由 • IntentやBundleのListの扱いがSerializableよりParcelableが型安全 • Serializableよりパフォーマンス面に優れているParcelableを利用 18
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>
Serializable vs Parcelable Serizliable • Java • 実装が楽 • 処理速度が遅め
• メモリ消費大 20 Parcelable • Android固有 • 実装が面倒(プラグインで自動生成が可能) • 処理速度が速め • メモリ消費小
Serializableと比較してParcelableがパフォーマンス優勢な理由 • リフレクションしていない ◦ writeToParcelで明示的に書き出す対象を指定するので解析の手間がなく、実行時の処理が速い • writeString, readString などの専用メソッドにより効率化 ◦
余計なGCのオーバーヘッドを削減 • Parcelの内部実装で最適化が行われている ◦ メモリマッピングなど • オブジェクトの循環参照を回避している ◦ 循環参照が発生する可能性がある場合、IDを利用して既にデシリアライズされたものを再利用したり、呼 び出された時に参照を解決したりして解決できる 21
モデルの相互変換 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, )
まとめ 23
まとめ • ActivityやFragment間のデータ受け渡しはSerializableよりParcelableが優秀 ◦ シリアライズの速度やメモリ効率もParcelableに軍配があがる ◦ ただし、永続化に使うのは避けること • @Parcelizeを活用すべし ◦
kotlin-parcelizeを導入しよう ◦ ボイラープレートを自動生成してくれて便利 • 役割ごとに型を分けて影響範囲を明確にする ◦ 今回は画面遷移時に引き渡されるパラメータとしてナビゲーションモデルを定義した ◦ ナビゲーションモデルはBundleに格納・取出することに集中する ◦ 遷移先でドメインモデルとして振る舞えるように相互変換を実装する 24
参考文献 • https://developer.android.com/kotlin/parcelize?hl=ja#skip_properties_from _serialization • https://developer.android.com/privacy-and-security/risks/unsafe-deserializ ation • https://outcomeschool.com/blog/parcelable-vs-serializable •
https://mixi-inc.github.io/AndroidTraining/fundamentals/2.07.serialize-and- collection-and-perpetuation.html#直列化 • Gemini Advanced 2.0 Flash 25