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
kobayashi_kento
April 24, 2025
Technology
0
55
Serializable / Parcelableとの上手な付き合い方
2025年4月24日(木)開催のpixiv App Nightで発表した資料です。
kobayashi_kento
April 24, 2025
Tweet
Share
More Decks by kobayashi_kento
See All by kobayashi_kento
Kotlinの好きなところ
kobaken0029
0
980
Compose駆動開発のためのマルチモジュール化
kobaken0029
0
210
DataStoreを導入してみた
kobaken0029
1
320
Epoxyを用いたレイアウト構築術
kobaken0029
1
230
Androidエンジニアが1週間でiOSアプリ開発を学び、1ヶ月で大規模アプリ開発にJOINした話
kobaken0029
0
3.2k
Modern REST Communicate for Android
kobaken0029
0
1.5k
AndroidでモダンREST通信してみたった
kobaken0029
0
250
Other Decks in Technology
See All in Technology
AIでテストプロセス自動化に挑戦する
sakatakazunori
1
590
AIエージェントが書くのなら直接CloudFormationを書かせればいいじゃないですか何故AWS CDKを使う必要があるのさ
watany
20
7.7k
マルチプロダクト環境におけるSREの役割 / SRE NEXT 2025 lunch session
sugamasao
1
800
第64回コンピュータビジョン勉強会「The PanAf-FGBG Dataset: Understanding the Impact of Backgrounds in Wildlife Behaviour Recognition」
x_ttyszk
0
250
Semantic Machine Intelligence for Vision, Language, and Actions
keio_smilab
PRO
2
330
Bill One 開発エンジニア 紹介資料
sansan33
PRO
4
13k
SREのためのeBPF活用ステップアップガイド
egmc
2
1.4k
QuickSight SPICE の効果的な運用戦略~S3 + Athena 構成での実践ノウハウ~/quicksight-spice-s3-athena-best-practices
emiki
0
300
[SRE NEXT 2025] すみずみまで暖かく照らすあなたの太陽でありたい
carnappopper
2
640
ClaudeCode_vs_GeminiCLI_Terraformで比較してみた
tkikuchi
1
3.1k
アクセスピークを制するオートスケール再設計: 障害を乗り越えKEDAで実現したリソース管理の最適化
myamashii
1
750
Maintainer Meetupで「生の声」を聞く ~講演だけじゃないKubeCon
logica0419
0
130
Featured
See All Featured
Making Projects Easy
brettharned
116
6.3k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Designing for Performance
lara
610
69k
Into the Great Unknown - MozCon
thekraken
40
1.9k
Thoughts on Productivity
jonyablonski
69
4.7k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
26k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Music & Morning Musume
bryan
46
6.7k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
4 Signs Your Business is Dying
shpigford
184
22k
How to Think Like a Performance Engineer
csswizardry
25
1.7k
KATA
mclloyd
30
14k
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