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
Mohit S
July 27, 2021
Programming
3
1.1k
Kotlin State & Shared Flows in Action
Shared Flow APIs
Mohit S
July 27, 2021
Tweet
Share
More Decks by Mohit S
See All by Mohit S
Guide to Improving Compose Performance
heyitsmohit
0
43
Building Shared UIs across Platforms with Compose
heyitsmohit
1
430
Building Multiplatform Apps with Compose
heyitsmohit
2
340
Building StateFlows with Jetpack Compose
heyitsmohit
6
1.6k
Building Android Testing Infrastructure
heyitsmohit
1
350
Migrating to Kotlin State & Shared Flows
heyitsmohit
1
610
Using Square Workflow for Android & iOS
heyitsmohit
1
340
Building Android Infrastructure Teams at Scale
heyitsmohit
2
250
Strategies for Migrating to Jetpack Compose
heyitsmohit
2
460
Other Decks in Programming
See All in Programming
さきがけから振り返るアーキテクチャ刷新 / Reflecting on the Architectural Renewal from the Vanguard
nrslib
2
780
なぜ宣言的 UI は壊れにくいのか / Why declarative UI is less fragile
uenitty
29
13k
CSC307 Lecture 12
javiergs
PRO
0
220
英語
s_shimotori
1
220
Rustのweb開発を助ける 便利なツール紹介
yuki0418
1
190
Introduction of Happy Eyeballs Version 2 (RFC8305) to the Socket library
coe401_
1
220
From Spring Boot 2 to Spring Boot 3 with Java 22 and Jakarta EE
ivargrimstad
0
1.9k
CSC307 Lecture 14
javiergs
PRO
0
220
[After Kotlin Fest 2024 LT Night @ Sansan] もっともっとKotlinを好きになる!K2 Compiler Pluginで遊んでみよう!
kitakkun
2
260
わかりやすい正解を捨てて、コトに向き合う - スクラムフェス金沢2024 スポンサーセッション
yusukekokubo
0
170
APIのない大学ログインWebサービスをWKWebViewとJavaScriptでアプリ化した話
akidon0000
1
330
Prompt FlowによるLLMアプリケーション開発
yuto2000
1
1k
Featured
See All Featured
Fireside Chat
paigeccino
25
2.8k
Designing with Data
zakiwarfel
96
5k
Rails Girls Zürich Keynote
gr2m
93
13k
Bootstrapping a Software Product
garrettdimon
PRO
304
110k
Building a Modern Day E-commerce SEO Strategy
aleyda
25
6.7k
StorybookのUI Testing Handbookを読んだ
zakiyama
15
4.9k
What’s in a name? Adding method to the madness
productmarketing
PRO
21
2.9k
For a Future-Friendly Web
brad_frost
173
9.2k
Large-scale JavaScript Application Architecture
addyosmani
506
110k
ParisWeb 2013: Learning to Love: Crash Course in Emotional UX Design
dotmariusz
105
6.8k
Designing Experiences People Love
moore
136
23k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
189
16k
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