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
1.4k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
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
340
Building Shared UIs across Platforms with Compose
heyitsmohit
1
730
Building Multiplatform Apps with Compose
heyitsmohit
2
640
Building StateFlows with Jetpack Compose
heyitsmohit
6
2k
Building Android Testing Infrastructure
heyitsmohit
1
650
Migrating to Kotlin State & Shared Flows
heyitsmohit
1
900
Using Square Workflow for Android & iOS
heyitsmohit
1
550
Building Android Infrastructure Teams at Scale
heyitsmohit
3
440
Strategies for Migrating to Jetpack Compose
heyitsmohit
2
680
Other Decks in Programming
See All in Programming
Building a Meta Ray-Ban display app
akkeylab
0
160
FDEが実現するAI駆動経営の現在地
gonta
2
290
言葉の格闘技のススメ~紙とペンと言葉から始める、キャリアの描き方~
progresscicada
2
160
SlackアプリとLambdaの 連携を構築した話
pawn_4_s
1
120
数百円から始めるRuby電子工作
tarosay
0
160
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
520
運用ダッシュボードの設計を誰も教えてくれないのだけどみなさんどうしてるんですか? - チームに監視するという文化を根付かせるための第一歩を踏みたい -
satoshi256kbyte
1
130
ソフトウェア設計に溶けるインフラ ― AWS CDK のインフラ認識論
konokenj
3
800
琵琶湖の水は止められてもNet--HTTPのリトライは止められない / You might be able to stop the water flow of Lake Biwa but you can't stop Net::HTTP retries
luccafort
PRO
0
770
Jindong: Introducing Declarative Haptics in Compose Multiplatform
l2hyunwoo
0
120
生成AIで帳票OCRが「簡単に」作れる時代になった?
kon_shou
0
1.1k
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
310
Featured
See All Featured
The Invisible Side of Design
smashingmag
301
52k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
230
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
1
400
Claude Code のすすめ
schroneko
67
230k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
800
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.8k
Into the Great Unknown - MozCon
thekraken
41
2.7k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
470
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
420
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
420
Measuring & Analyzing Core Web Vitals
bluesmoon
9
960
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