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
Extension functions for LiveData
Search
Hiroyuki Kusu
August 21, 2020
Programming
530
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Extension functions for LiveData
Yumemi.apk #1 (
https://yumemi.connpass.com/event/180842/
) の資料
Hiroyuki Kusu
August 21, 2020
More Decks by Hiroyuki Kusu
See All by Hiroyuki Kusu
モノレポのプルリクエストに最近、導入したもの
hkusu
2
600
GitHub composite actions
hkusu
2
460
Android の静的解析における SARIF ファイルの活用
hkusu
0
5.7k
CI_でライブラリのバージョンの変化をレポートする.pdf
hkusu
0
430
Maestro を GitHub Actions で動かす 〜Android編〜
hkusu
1
1.8k
Android の CI(GitHub Actions)の改善で、最近やったこと
hkusu
0
740
Tauri Mobile で生成される Android のコードを見てみる
hkusu
0
1.6k
Custom GitHub Actions を作って Organization 内で共有する
hkusu
1
610
GitHub Actions でユニットテストの結果をレポートする
hkusu
0
3.9k
Other Decks in Programming
See All in Programming
Deep dive into the select statement (GopherCon UK)
jespino
0
170
LL言語やWebフレームワークのPostgreSQL対応 〜DBの機能がユーザーに届くまで〜
kentaroutakeda
0
130
Oxlintはいいぞ(続)
yug1224
1
540
自分的「カンファレンスの楽しみ方」
syumai
0
190
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
140
AI に Inclusive UI を書かせよう — Design Rules Skill で Compose UI を作り直す
theoriatec2024
1
440
「つくるAI」だけではバグは見つからない ~テストに必要な「見つけるAI」を分離させる戦略~
mfunaki
0
230
From 6 People Classroom Meetup to 100 People Regional Conference / FOSS4G Hiroshima 2026
furukawayasuto
0
100
Can LLMs Replicate 4 Years of Compose Migration? Exploring the boundaries of automation with 279 XML files from a real product
makun
0
130
AIに既存システムを理解させる技術 ~レガシーを見捨てないハーネスエンジニアリング入門~
ochtum
0
200
MySQLとPostgreSQLって何が違うの?
akagami
PRO
0
160
AIと壁打ちしながら進めるコスト管理
fufuhu
2
1.9k
Featured
See All Featured
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
Product Roadmaps are Hard
iamctodd
55
13k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.2k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
490
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
Automating Front-end Workflow
addyosmani
1369
210k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
800
Become a Pro
speakerdeck
PRO
31
6.2k
Deep Space Network (abreviated)
tonyrice
0
290
Building an army of robots
kneath
306
46k
Docker and Python
trallard
47
4.2k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
500
Transcript
Extension functions for LiveData 2020.08.21 YUMEMI.apk #1 Hiroyuki Kusu (
@hkusu_ )
About me
https://speakerdeck.com/hkusu/unit-test-for-viewmodel-and-livedata ࠓճ ↑ ʹ࣌ؒతʹؚΊΔ͜ͱ͕ग़དྷͳ͔ͬͨ
ViewModel தͷ LiveData ͷهड़ private val _liveData1: MutableLiveData<Int> = MutableLiveData()
val liveData1: LiveData<Int> = _liveData1 val liveData2: LiveData<Boolean> = liveData1.map { // ... } "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" • σʔλͷؔ࿈ੑ͕એݴతʹఆٛ͞Ε͍ͯΔͱ͔Γ͍͢ • ͬͱศརʹ͍ͨ͠..! • ࣗલͰ࡞֦ͨ͠ுؔΛɺ͍͔ͭ͘հ͠·͢
fun <T, U> LiveData<T>.coMap( coroutineScope: CoroutineScope, coroutineContext: CoroutineContext = coroutineScope.coroutineContext,
block: suspend (T) -> U ): LiveData<U> { val result = MediatorLiveData<U>() result.addSource(this) { coroutineScope.launch(coroutineContext) { result.postValue(block.invoke(it)) } } return result } ※ switchMap() ͱ livedata {} ΛΈ߹Θͤͯಉ͜͡ͱ͕Ͱ͖·͢ ※ ݱঢ়Ͱ inline fun ʹ͢ΔͱམͪΔ https://github.com/Kotlin/kotlinx.coroutines/issues/ coMap val liveData2: LiveData<List<SampleItem>> = liveData1.coMap(viewModelScope) { it: Int delay(3_000) sampleRepository.getItemList(it) // suspending function } ར༻Πϝʔδ ؔͷఆٛ
val liveData3: LiveData<String> = merge(liveData1, liveData2) { i: Int?, b:
Boolean? -> // ... } inline fun <T1, T2, U> merge( liveData1: LiveData<T1>, liveData2: LiveData<T2>, crossinline block: (T1?, T2?) -> U? ): LiveData<U> { val result = MediatorLiveData<U>() result.addSource(liveData1) { t1 -> block.invoke(t1, liveData2.value)?.takeUnless { it is Unit }?.let { result.value = it } } result.addSource(liveData2) { t2 -> block.invoke(liveData1.value, t2)?.takeUnless { it is Unit }?.let { result.value = it } } return result } merge ར༻Πϝʔδ ؔͷఆٛ (֦ுؔͰͳ͘ී௨ͷؔ) block தͰ LiveDataͷߋ৽ΛΩϟϯηϧͰ͖ΔΑ͏ʹ͢Δҝͷॲஔ (Ωϟϯηϧ͍ͨ͠߹null͘͠Γͳ͠Ͱreturn͢Δ)
val liveData2: LiveData<Int> = liveData1.filter { 100 < it }
inline fun <T> LiveData<T>.filter( crossinline block: (T) -> Boolean ): LiveData<T> { val result = MediatorLiveData<T>() result.addSource(this) { if (block.invoke(it)) { result.value = it } } return result } filter ར༻Πϝʔδ ؔͷఆٛ
val liveData2: LiveData<Int> = liveData1.map { // ... }.coMap(viewModelScope) {
// ... }.map { // ... }.coMap(viewModelScope) { // ... }.filter { // ... } ͭͳ͛ͯॻ͚Δ
͋ΔLiveDataͷมߋΛܖػʹͳʹ͔͠ΒͷॲཧΛ͍͕ͨ͠.. ( LiveData ͷͭͳ͕Γ͚ͩͰ্ख͘ઃܭͰ͖ͳ͍έʔε ) val liveData2: LiveData<Boolean> = liveData1.map
{ } ແ༻ͳ LiveData2 Λఆٛͯ͠ɺLiveData2 ͷ Observer ͕ډͳ͍߹ ͜ͷϒϩοΫ࣮ߦ͞Εͳ͍
val observe = liveData1.map { }.observe() // ... override fun
onCleared() { observe.cancel() } class Observe<T>(private val liveData: LiveData<T>) { private val observer = Observer<T> {} fun start() { liveData.observeForever(observer) } fun cancel() { liveData.removeObserver(observer) } } fun <T> LiveData<T>.observe(): Observe<T> = Observe(this).apply { start() } observe ViewModel ͷഁغ࣌ʹ؍ଌΛऴྃͤ͞Δඞཁ observeForever Λར༻ ͜ͷϒϩοΫͰҙͷॲཧ ؔͷఆٛ ར༻Πϝʔδ
https://gist.github.com/hkusu/b258c4e4ef488ccd8b213586417ffbec ࠓճɺհ֦ͨ͠ுؔgistʹஔ͖·ͨ͠
Thank you ! @hkusu_