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
Kotlin State & Shared Flows in Action
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Mohit S
July 27, 2021
Programming
1.4k
4
Share
Kotlin State & Shared Flows in Action
Shared Flow APIs
Mohit S
July 27, 2021
More Decks by Mohit S
See All by Mohit S
Guide to Improving Compose Performance
heyitsmohit
0
310
Building Shared UIs across Platforms with Compose
heyitsmohit
1
700
Building Multiplatform Apps with Compose
heyitsmohit
2
590
Building StateFlows with Jetpack Compose
heyitsmohit
6
2k
Building Android Testing Infrastructure
heyitsmohit
1
600
Migrating to Kotlin State & Shared Flows
heyitsmohit
1
850
Using Square Workflow for Android & iOS
heyitsmohit
1
500
Building Android Infrastructure Teams at Scale
heyitsmohit
3
390
Strategies for Migrating to Jetpack Compose
heyitsmohit
2
630
Other Decks in Programming
See All in Programming
Feature Toggle は捨てやすく使おう
gennei
0
430
瑠璃の宝石に学ぶ技術の声の聴き方 / 【劇場版】アニメから得た学びを発表会2026 #エンジニアニメ
mazrean
0
160
Swift Concurrency Type System
inamiy
0
110
Symfonyの特性(設計思想)を手軽に活かす特性(trait)
ickx
0
130
「効かない!」依存性注入(DI)を活用したAPI Platformのエラーハンドリング奮闘記
mkmk884
0
300
Strategy for Finding a Problem for OSS: With Real Examples
kibitan
0
140
PHP でエミュレータを自作して Ubuntu を動かそう
m3m0r7
PRO
2
170
脱 雰囲気実装!AgentCoreを良い感じにWEBアプリケーションに組み込むために
takuyay0ne
3
440
実践ハーネスエンジニアリング #MOSHTech
kajitack
7
5.9k
安いハードウェアでVulkan
fadis
1
910
生成 AI 時代のスナップショットテストってやつを見せてあげますよ(α版)
ojun9
0
340
年間50登壇、単著出版、雑誌寄稿、Podcast出演、YouTube、CM、カンファレンス主催……全部やってみたので面白さ等を比較してみよう / I’ve tried them all, so let’s compare how interesting they are.
nrslib
4
710
Featured
See All Featured
Prompt Engineering for Job Search
mfonobong
0
250
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
27
3.4k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
200
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
410
Embracing the Ebb and Flow
colly
88
5k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
1
1.5k
Skip the Path - Find Your Career Trail
mkilby
1
100
Side Projects
sachag
455
43k
Building AI with AI
inesmontani
PRO
1
860
Design in an AI World
tapps
0
190
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
510
Transcript
Mohit Sarveiya Kotlin State & Shared Flows in Action @heyitsmohit
Kotlin State & Shared Flows in Action • State Flow
• Shared Flow • Broadcast Channel vs shared flow • Convert cold streams to shared flows • Buffer Overflow Strategies
Cold vs Hot Flows
What is a cold stream? A cold stream is a
flow that triggers the same code every time it is collected.
Cold Flows val flow = flowOf(1, 2, 3) .map
{ it + 1 }
Cold Flows val flow = flowOf(1, 2, 3) .map
{ it + 1 } flow.collect { ... }
Cold Flows val flow = flowOf(1, 2, 3) .map
{ it + 1 } flow.collect { ... }
Cold Flows val flow = flowOf(1, 2, 3) .map
{ it + 1 } flow.collect { ... }
Cold Flows val flow = flowOf(1, 2, 3) .map
{ it + 1 } flow.collect { // 2, 3, 4 }
Cold Flows val flow = flowOf(1, 2, 3) .map
{ it + 1 } flow.collect { ... } flow.collect { ... }
Cold Flows val flow = flowOf(1, 2, 3) .map
{ it + 1 } flow.collect { ... } flow.collect { ... }
Cold Flows val flow = flowOf(1, 2, 3) .map
{ it + 1 } flow.collect { ... } flow.collect { // 2, 3, 4 }
What is a hot stream? A hot stream is a
flow whose active instance exists independently of the presence of collectors.
Hot Streams State Flow Shared Flow
State Flow View View Model
State Flow View View Model
State Flow View View Model State
State Flow sealed class UiState { data class Error(
val exception: Throwable ): UiState() }
State Flow sealed class UiState { data class Success(
val data: Data ): UiState() data class Error( val exception: Throwable ): UiState() }
State Flow sealed class UiState { data class Success(
val data: Data ): UiState() data class Error( val exception: Throwable ): UiState() }
State Flow val uiState = MutableStateFlow()
val uiState = MutableStateFlow( UiState.Success(Data()) ) State Flow
State Flow val uiState = MutableStateFlow( . .. ) uiState.emit(
UIState.Success(Data()) )
State Flow val uiState = MutableStateFlow( . .. ) uiState.value
= UIState.Success(Data())
State Flow val uiState = MutableStateFlow( . .. ) uiState.collect
{ ... } Latest value is received
State Flow val uiState = MutableStateFlow( . .. ) uiState.collect
{ ... } uiState.collect { ... } Latest value is received
State Flow Conflation val uiState = MutableStateFlow( . .. )
uiState.value = UIState.Success( .. . ) uiState.value = UIState.Error( .. . ) Conflate
State Flow Conflation val uiState = MutableStateFlow( . .. )
uiState.value = UIState.Success( .. . ) uiState.value = UIState.Error( .. . ) uiState.collect { ... } Error
State Flow vs Live Data State Flow Live Data Default
Value Unsubscribe (Stopped State)
State Flow vs Live Data State Flow Live Data Default
Value Unsubscribe (Stopped State)
State Flow vs Live Data State Flow Live Data Default
Value Unsubscribe (Stopped State)
State Flow Summary • How to setup state flow •
Emit and collect • State Flow vs Live Data
Shared Flow
Shared Flow
Shared Flow Consumer 1 Consumer 2
Shared Flow Consumer 1 Consumer 2
Shared Flow Consumer 1 Consumer 2 Event Event
Shared Flow Consumer 1 Consumer 2 Replay Replay
Shared Flow Buffer
Shared Flow val flow = MutableSharedFlow < > ()
Shared Flow val flow = MutableSharedFlow<String>()
Shared Flow val flow = MutableSharedFlow<String>()
Shared Flow val flow = MutableSharedFlow<String>() launch { flow.collect {
} }
Shared Flow val flow = MutableSharedFlow<String>() launch { flow.emit("Event
1") } launch { flow.collect { } }
Shared Flow val flow = MutableSharedFlow<String>() launch { flow.emit("Event
1") } launch { flow.collect { } } Event 1
Shared Flow val flow = MutableSharedFlow<String>() launch { flow.emit("Event
1”) } launch { delay(2000); flow.collect { } }
Shared Flow val flow = MutableSharedFlow<String>() launch { delay(2000);
flow.collect { } } launch { flow.emit("Event 1”) }
Shared Flow val flow = MutableSharedFlow<String>() launch { delay(2000);
flow.collect { } } launch { flow.emit("Event 1”) }
Shared Flow val flow = MutableSharedFlow<String>() launch { delay(2000);
flow.collect { } } No value is received launch { flow.emit("Event 1”) }
Shared Flow val flow = MutableSharedFlow<String>() launch { flow.emit("Event
1”) } launch { delay(2000); flow.collect { } } Replay
Shared Flow val flow = MutableSharedFlow<String>(replay = 1) launch
{ flow.emit("Event 1”) } launch { delay(2000); flow.collect { } }
Shared Flow val flow = MutableSharedFlow<String>(replay = 1) launch
{ delay(2000); flow.collect { } } launch { flow.emit("Event 1”) } Event 1
val flow = MutableSharedFlow<String>(replay = 1) Shared Flow State
Flow launch { flow.collect { } } launch { flow.subscriptionCount.value }
Shared Flow val flow = MutableSharedFlow<String>(replay = 1) 1 Subscriber
launch { flow.collect { } } launch { flow.subscriptionCount.value }
Shared Flow val flow = MutableSharedFlow<String>(replay = 1) Shared Flow
does not complete normally launch { flow.collect { } }
Cold Flows val flow = flowOf(1, 2, 3) flow
.onCompletion { } .collect { ... } Flow completes normally
Shared Flow val flow = MutableSharedFlow<String>(replay = 1) val job
= launch { flow.collect { } } job.cancel()
Shared Flow val flow = MutableSharedFlow<String>(replay = 1) val job
= launch { flow.onCompletion { }.collect { } } job.cancel() Flow completes exceptionally
Shared Flow Summary • Setup • Replay and emit •
Cancellation
Broadcast Channel vs Shared Flow
Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed
val channel = BroadcastChannel<Int>(10)
val channel = BroadcastChannel<Int>(10) channel.send( ... )
val channel = BroadcastChannel<Int>(10) channel.send( ... ) channel.close()
val stateFlow = MutableSharedFlow() stateFlow.emit( ... )
Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed
val stateFlow = MutableSharedFlow(replay = 2) stateFlow.emit( ... )
Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed
val channel = BroadcastChannel<Int>(capacity = 10) channel.send( ... )
val stateFlow = MutableSharedFlow( replay = 2, extraBufferCapacity = 10
) stateFlow.emit( ... )
Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed
val channel = BroadcastChannel<Int>(10) channel.send( ... ) channel.close()
val stateFlow = MutableSharedFlow( replay = 2, extraBufferCapacity = 10
) stateFlow.emit( ... )
Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed
Broadcast Channel Shared Flow
val channel = BroadcastChannel<Int>(capacity)
val channel = BroadcastChannel<Int>(capacity) val flow = MutableSharedFlow<String>(extraBufferCapacity)
channel.send( ... ) channel.trySend( ... ) flow.emit( ... ) flow.tryEmit(
... )
Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed
Flow Sharing Strategies
Cold Flow Hot Flow Convert
Sharing Policies • While Subscribed • Eagerly • Lazily
Sharing Policies flow
Sharing Policies flow.shareIn( )
Sharing Policies flow.shareIn( externalScope, )
Sharing Policies flow.shareIn( externalScope, replay = 1, )
Sharing Policies flow.shareIn( externalScope, replay = 1, started = SharingStarted.WhileSubscribed()
)
Sharing Policies val sharedFlow = flow.shareIn( externalScope, replay = 1,
started = SharingStarted.WhileSubscribed() )
While Subscribed • Active as long as external scope is
alive • Remains as long as there are collectors.
Properties Active as long as external scope is alive
Properties Active as long as external scope is alive sharedFlow.collect
{ } Subscriber
flow.shareIn( externalScope, replay = 1, started = SharingStarted.WhileSubscribed() ) Properties
Active as long as external scope is alive
Properties Active as long as external scope is alive sharedFlow.collect
{ } externalScope.cancel()
Properties Active as long as external scope is alive sharedFlow.collect
{ } externalScope.cancel() Complete Exceptionally
Properties Remains as long as there are collectors.
Properties Remains as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…)
Properties Remains as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } }
Properties Remains as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } } job.cancel()
Properties Remains as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } } job.cancel()
Properties Remains as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } } job.cancel()
Properties Remains as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) val job1 = launch { sharedFlow.collect { } } val job2 = launch { sharedFlow.collect { } }
Properties Remains as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) job1.cancel() val job2 = launch { sharedFlow.collect { } }
Properties Remains as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) job1.cancel() val job2 = launch { sharedFlow.collect { } } Remain Active
Properties • Active as long as external scope is alive
• Remains as long as there are collectors.
Sharing Policies • While Subscribed • Eagerly • Lazily
Eagerly flow.shareIn( externalScope, replay = 1, started = SharingStarted.Eagerly() )
Eagerly Start producer eagerly and never stop flow .onStart {
println("ON START") } .shareIn( ... started = SharingStarted.Eagerly)
Eagerly Start producer eagerly and never stop flow .onStart {
println("ON START") } .shareIn( ... started = SharingStarted.Eagerly)
Eagerly Start producer eagerly and never stop flow .onStart {
println("ON START") } .shareIn( ... started = SharingStarted.Eagerly) ON START
Eagerly Start producer eagerly and never stop flow .onComplete {
println("ON COMPLETE”) } .shareIn( ... started = SharingStarted.Eagerly)
Eagerly Start producer eagerly and never stop flow .onComplete {
println("ON COMPLETE”) } .shareIn( ... started = SharingStarted.Eagerly) externalScope.cancel()
Eagerly Start producer eagerly and never stop flow .onComplete {
println("ON COMPLETE”) } .shareIn( ... started = SharingStarted.Eagerly) Never stops externalScope.cancel()
Eagerly Start producer eagerly and never stop
Sharing Policies • While Subscribed • Eagerly • Lazily
Lazily Start sharing after the first subscriber appears and never
stop
Lazily flow.shareIn( externalScope, replay = 1, started = SharingStarted.Lazily )
Lazily flow .onStart { println("ON START") } .shareIn(…,started = SharingStarted.Lazily)
Lazily flow .onStart { println("ON START") } .shareIn(…,started = SharingStarted.Lazily)
launch { sharedFlow.collect { } }
Lazily flow .onStart { println("ON START") } .shareIn(…,started = SharingStarted.Lazily)
launch { sharedFlow.collect { } } "ON START"
Lazily flow .onCompletion { println("COMPLETE") } .shareIn(…,started = SharingStarted.Lazily)
flow .onCompletion { println("COMPLETE") } .shareIn(externalScope,…,started = SharingStarted.Lazily) Lazily
flow .onCompletion { println("COMPLETE") } .shareIn(externalScope,…,started = SharingStarted.Lazily) Lazily externalScope.cancel()
flow .onCompletion { println("COMPLETE") } .shareIn(externalScope,…,started = SharingStarted.Lazily) Lazily Never
stops externalScope.cancel()
Lazily Start sharing after the first subscriber appears and never
stop
Sharing Policies • While Subscribed • Active while there are
active subscribers. • Eagerly • Start producer eagerly and never stop • Lazily • Start after the first subscriber appears and never stop
Buffer Overflow Strategies
Shared Flow Buffer
Shared Flow Producer Consumer
Shared Flow Producer Consumer Generating events fast
Shared Flow Producer Consumer Listening to events with
delay
Shared Flow Producer Consumer
Shared Flow Producer Consumer
Shared Flow Producer Consumer What happens when it is
full?
Buffering Overflow Strategies • Suspend • Drop oldest • Drop
latest
Shared Flow Producer Consumer Suspend
Buffering Overflow Strategies val flow = MutableSharedFlow<String>( extraBufferCapacity = 2,
onBufferOverflow = BufferOverflow.SUSPEND ) Buffer + Replay Count
Buffering Overflow Strategies val flow = MutableSharedFlow<String>( extraBufferCapacity = 2,
onBufferOverflow = BufferOverflow.SUSPEND )
Buffering Overflow Strategies launch { flow.emit("Event 1") flow.emit("Event 2") flow.emit("Event
3") } Suspend
Buffering Overflow Strategies • Suspend • Drop oldest • Drop
latest
Shared Flow Producer Consumer Drop Oldest
Shared Flow Producer Consumer Drop latest
Buffering Overflow Strategies • Suspend • Drop oldest • Drop
latest
Kotlin State & Shared Flows in Action • State Flow
• Shared Flow • Broadcast Channel vs shared flow • Convert cold streams to shared flows • Buffer Overflow Strategies
https: // codingwithmohit.com/coroutines/learning-shared-and-state-flows-with-tests/ Coding with Mohit
Thank You! www.codingwithmohit.com @heyitsmohit