Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Implementation of API call state using sealed c...
Search
Hideyuki Kikuma
January 16, 2020
Programming
2.8k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Implementation of API call state using sealed class
Hideyuki Kikuma
January 16, 2020
More Decks by Hideyuki Kikuma
See All by Hideyuki Kikuma
Talk about still using minSdkVersion=7
hidey
1
580
AndroidとIPv6
hidey
1
1.2k
Other Decks in Programming
See All in Programming
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
220
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
160
TiDB Cloudのカスタムコントローラーによるオートスケール対応
takaidohigasi
0
130
Are APIs Still Relevant in the AI Era?
soyuka
0
310
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
300
FreeBSDでZabbixを動かす
kenkino
0
320
MVNOの申込からeSIM開通までをiOSアプリでつなぐ- 本人確認・MNP・通信事業者基盤をまたぐ実装
satotakeshi
0
470
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
360
巨大モノリシックアプリ モダン化大作戦
ktcryomm
1
1.1k
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
210
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
250
iOSDC2026登壇資料.pdf
riofujimon
0
180
Featured
See All Featured
Everyday Curiosity
cassininazir
0
330
XXLCSS - How to scale CSS and keep your sanity
sugarenia
250
1.3M
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
How to build a perfect <img>
jonoalderson
1
6k
Abbi's Birthday
coloredviolet
4
10k
The Pragmatic Product Professional
lauravandoore
37
7.5k
Optimising Largest Contentful Paint
csswizardry
37
4k
Navigating Weather and Climate Data
rabernat
0
530
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
710
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
300
Transcript
API通信の状態を sealed classを使って表現する Bonfire Android #6
自己紹介 @hidey / 菊間 英行 株式会社メルペイ Android エンジニア DroidKaigi スタッフ
API通信中の状態とか 困ったりしてませんか?
よくある画面表示の要件 • 画面表示には API から取ってきた情報が必要 ◦ 初期表示はデフォルト表示の場合と何も表示したくないパターンどっちもありそう • ロード中は progress
表示にしたい • API のレスポンスが返ってきたらその内容を表示 • API がエラーだった場合はエラー画面表示にしたい • エラー画面に再読み込みボタンを付けたい
None
つまり画面の状態としてはざっくり4つ • 初期状態 • ロード中 • データ取得完了 • データ取得エラー
メルペイではRemoteDataKを使っている 内部で使っていたライブラリを OSS 化したもの • 状態を表現する sealed class • 便利関数
(map, mapError など ) メルペイの用途ではこれで満足できている https://github.com/mercari/RemoteDataK
コードで表すとこんな感じ sealed class RemoteData<out V : Any, out E :
Exception> { object Initial : RemoteData<Nothing, Nothing>() class Loading<V : Any>(progress: Int? = null, val total: Int = 100) : RemoteData<V, Nothing>() class Success<out V : Any>(val value: V) : RemoteData<V, Nothing>() class Failure<out E : Exception>(val error: E) : RemoteData<Nothing, E>() }
素朴なstate実装 data class SampleState( val entity: SampleEntity? = null, val
error: Exception? = null, val isLoading: Boolean = false ) data class SampleEntity( val title: String, val items: List<String> )
その場合のStateの変更箇所のコード class SampleReducer { fun reduce(action: Action, currentState: SampleState): SampleState
= when (action) { is ShowDataAction -> { if (action.result.isSuccess) { currentState.copy(entity = action.result.entity, isLoading = false) } else { currentState.copy(error = action.result.error, isLoading = false) } } is LoadData -> currentState.copy(isLoading = true, entity = null, error = null) else -> currentState } }
その場合のView周りのコード fun updateView(state: SampleState) { if (state.entity != null) {
titleView.text = state.entity.title adapter.items = state.entity.items } if (state.error != null) { errorMessage.text = state.error.localizedMessage } errorView.isVisible = state.error != null loadingView.isVisible = state.isLoading }
RemoteDataで書き直してみる data class SampleState( val entity: RemoteData<SampleEntity, Exception> = RemoteData.Initial
) data class SampleEntity( val title: String, val items: List<String> )
その場合のStateの変更箇所のコード class SampleReducer { fun reduce(action: Action, currentState: SampleState): SampleState
= when (action) { is ShowDataAction -> { if (action.result.isSuccess) { currentState.copy(entity = RemoteData.Success(action.result.entity)) } else { currentState.copy(entity = RemoteData.Failure(action.result.error)) } } is LoadData -> currentState.copy(entity = RemoteData.Loading()) else -> currentState } }
その場合のView周りのコード fun updateView(state: SampleState) { when (val entity = state.entity)
{ is RemoteData.Success -> { titleView.text = entity.value.title adapter.items = entity.value.items } is RemoteData.Failure -> errorMessage.text = entity.error.localizedMessage } errorView.isVisible = state.entity.isFailure loadingView.isVisible = state.entity.isLoading }
あれ? そんなに変わらなくない?
拡張関数を追加してみる fun <V : Any, E : RemoteError> Result<V, E>.toRemoteData():
RemoteData<V, E> = when (this) { is Result.Success -> RemoteData.Success(this.value) is Result.Failure -> RemoteData.Failure(this.error) }
Stateの変更箇所のコード class SampleReducer { fun reduce(action: Action, currentState: SampleState): SampleState
= when (action) { is ShowDataAction -> currentState.copy( entity = action.result.toRemoteData() ) is LoadData -> currentState.copy(entity = RemoteData.Loading()) else -> currentState } }
View周りでいいこととか statusObservable.map(SampleState::entity) .map { it.value.title } // title が nonnull
である必要がある .distinctUntilChanged() .subscribe { updateTitle(it) }
課題もある
例えばkotlinx.serializationが使えない • AAC の ViewModel で状態管理をしたい場合、 Bundle に入れられる型が必要 • kotlinx.serialization
で Serializable にしたい • RemoteDataK の Failure は java の Exception を持っている • これは kotlinx.serialization で Serializable に出来ない このため、アドホックなコードで対応してる
詳しくはこちら https://tech.mercari.com/entry/2019/12/04/100000 https://tech.mercari.com/entry/2019/12/18/100000
今日のサンプルコード https://github.com/hidey/remote_data_sample
まとめ • sealed class を使うと状態 + 値の組み合わせをうまく表現できる • 一つのプロパティにまとまるので関数で処理しやすい •
ロード中などの状態を全体で統一した表現に出来る • NullObject を作らずに nonnull に出来るので Rx と相性がいい
ご静聴ありがとうございました