Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Migrating to Kotlin State & Shared Flows
Search
Mohit S
June 03, 2022
Programming
1
810
Migrating to Kotlin State & Shared Flows
Mohit S
June 03, 2022
Tweet
Share
More Decks by Mohit S
See All by Mohit S
Guide to Improving Compose Performance
heyitsmohit
0
260
Building Shared UIs across Platforms with Compose
heyitsmohit
1
660
Building Multiplatform Apps with Compose
heyitsmohit
2
540
Building StateFlows with Jetpack Compose
heyitsmohit
6
1.9k
Building Android Testing Infrastructure
heyitsmohit
1
530
Using Square Workflow for Android & iOS
heyitsmohit
1
450
Building Android Infrastructure Teams at Scale
heyitsmohit
3
340
Strategies for Migrating to Jetpack Compose
heyitsmohit
2
600
Challenges of Building Kotlin Multiplatform Libraries
heyitsmohit
1
460
Other Decks in Programming
See All in Programming
Module Harmony
petamoriken
2
600
チーム開発の “地ならし"
konifar
8
6.9k
Rediscover the Console - SymfonyCon Amsterdam 2025
chalasr
2
120
Socio-Technical Evolution: Growing an Architecture and Its Organization for Fast Flow
cer
PRO
0
200
関数の挙動書き換える
takatofukui
4
760
AIと協働し、イベントソーシングとアクターモデルで作る後悔しないアーキテクチャ Regret-Free Architecture with AI, Event Sourcing, and Actors
tomohisa
5
17k
ID管理機能開発の裏側 高速にSaaS連携を実現したチームのAI活用編
atzzcokek
0
160
バックエンドエンジニアによる Amebaブログ K8s 基盤への CronJobの導入・運用経験
sunabig
0
120
React Native New Architecture 移行実践報告
taminif
1
130
ローターアクトEクラブ アメリカンナイト:川端 柚菜 氏(Japan O.K. ローターアクトEクラブ 会長):2720 Japan O.K. ロータリーEクラブ2025年12月1日卓話
2720japanoke
0
350
DSPy Meetup Tokyo #1 - はじめてのDSPy
masahiro_nishimi
1
130
GeistFabrik and AI-augmented software development
adewale
PRO
0
230
Featured
See All Featured
Reflections from 52 weeks, 52 projects
jeffersonlam
355
21k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.7k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
119
20k
Become a Pro
speakerdeck
PRO
30
5.7k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.2k
Faster Mobile Websites
deanohume
310
31k
Java REST API Framework Comparison - PWX 2021
mraible
34
9k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.1k
Code Reviewing Like a Champion
maltzj
527
40k
Visualization
eitanlees
150
16k
The Cult of Friendly URLs
andyhume
79
6.7k
Unsuck your backbone
ammeep
671
58k
Transcript
Mohit Sarveiya Migrating to Kotlin State & Shared Flows @heyitsmohit
Migrating to Kotlin State & Shared Flows • State &
Shared Flow APIs • Migrating from broadcast channels • Flow Sharing Strategies • Manage Backpressure
Cold vs Hot Flows
What is a cold stream? • Flow completes • Triggers
same code for every new subscriber
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 { ... }
Cold Flows val flow = flowOf(1, 2, 3) .map
{ it + 1 } flow.collect { ... } flow.collect { // 2, 3, 4 }
What is a hot stream? • Never completes normally •
Exists independently of subscribers.
Hot Streams State Flow Shared Flow
State Flow • Different ways to create state flows •
Emit, collect • Conflation
State Flow View View Model
State Flow View View Model State
State Flow sealed class UiState { object Loading: UiState()
data class Success(…): UiState() data class Error(…): UiState() }
State Flow sealed class UiState { object Loading: UiState()
data class Success(…): UiState() data class Error(…): UiState() }
State Flow sealed class UiState { object Loading: UiState()
data class Success(…): UiState() data class Error(…): UiState() }
State Flow val stateFlow = MutableStateFlow()
val stateFlow = MutableStateFlow( UiState.Loading ) State Flow
State Flow val stateFlow = MutableStateFlow( . .. ) stateFlow.emit(
UIState.Success( ... ) )
State Flow val stateFlow = MutableStateFlow( . .. ) stateFlow.value
= UIState.Success( ... )
State Flow val stateFlow = MutableStateFlow( . .. ) stateFlow.update
{ UIState.Success( .. . ) }
State Flow val stateFlow = MutableStateFlow( . .. ) stateFlow.collect
{ .. . } stateFlow.collect { .. . } Latest value is received
State Flow Conflation val stateFlow = MutableStateFlow( . .. )
stateFlow.value = UIState.Success( ... ) stateFlow.value = UIState.Error( .. . ) Conflate
State Flow Conflation val stateFlow = MutableStateFlow( . .. )
stateFlow.value = UIState.Success( ... ) stateFlow.value = UIState.Error( .. . ) stateFlow.collect { .. . } Error
State Flow View View Model State
State Flow State Flow Flow 1 Flow 2 Flow 3
Combined Flow
Flow Combine 1 A 1A Flow 1 Flow 2 Combined
Flow Combine 1 2 A 1A 2A Flow 1 Flow
2 Combined
Flow Combine 1 2 A 1A 2A Flow 1 Flow
2 Combined B 2B
val stateFlow = MutableStateFlow(UIState.Loading) flow1.combine(flow2) { a, b -
> } State Flow
val stateFlow = MutableStateFlow(UIState.Loading) flow1.combine(flow2) { a, b -
> combineItems(a, b) } State Flow
val stateFlow = MutableStateFlow(UIState.Loading) flow1.combine(flow2) { a, b -
> combineItems(a, b) }.collect { stateFlow.emit(it) } State Flow
Flow Marbles
State Flow View View Model State
Cash App - Molecule
Molecule Purpose Build a StateFlow using Jetpack Compose
Approach View Molecule Presenter (Composable) Events
Presenter @Composable fun Presenter(eventFlow: Flow<Event>): UiState { val
event by eventFlow.collectAsState(null) return if (event = = null) { UiState.Loading } else { UiState.Data(…) } }
Presenter @Composable fun Presenter(eventFlow: Flow<Event>): UiState { val
event by eventFlow.collectAsState(null) return if (event = = null) { UiState.Loading } else { UiState.Data(…) } }
Presenter @Composable fun Presenter(eventFlow: Flow<Event>): UiState { val
event by eventFlow.collectAsState(null) return if (event = = null) { UiState.Loading } else { UiState.Data(…) } }
Setup Molecule Presenter (Composable)
Setup Molecule Presenter (Composable) StateFlow
Launching Molecule val scope = CoroutineScope(Dispatchers.Main) val models: StateFlow<UsersModel> =
scope.launchMolecule { userPresenter(postsFlow, likesFlow) }
Launching Molecule val flow: StateFlow<UiState> = scope.launchMolecule { presenter(eventFlow) }
Setup View Molecule
Setup View View Model
View Model class MyViewModel: ViewModel() { val stateFlow
= moleculeScope.launchMolecule { val event by eventFlow.collectAsState(null) return if (event == null) { UiState.Loading } else { UiState.Success(…) } }
Learn More https: / / youtu.be/rUpZSZedoHI
State Flow • Different ways to create state flows •
Emit, collect
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<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>(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
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 • Setup • Replay and emit • Cancellation
Broadcast Channel vs Shared Flow
Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed
val channel = BroadcastChannel<Int>(10) Broadcast Channel
val channel = BroadcastChannel<Int>(10) channel.send( ... ) Broadcast Channel
val channel = BroadcastChannel<Int>(10) channel.send( ... ) channel.close() Broadcast Channel
val flow = MutableSharedFlow() flow.emit( ... ) Shared Flow
Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed
val flow = MutableSharedFlow(replay = 2) flow.emit( ... ) Shared
Flow
Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed
val channel = BroadcastChannel<Int>(capacity = 10) channel.send( ... ) Broadcast
Channel
val flow = MutableSharedFlow( replay = 2, extraBufferCapacity = 10
) flow.emit( ... ) Shared Flow
Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed
Broadcast Channel Shared Flow
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
State Flow State Flow Flow 1 Flow 2 Flow 3
Combined Flow
Creating State & Shared Flows • shareIn • stateIn
Sharing Policies • While Subscribed • Eagerly • Lazily
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() )
Properties • Active as long as external scope is alive
• Remains as long as there are collectors.
Properties Active as long as external scope is alive externalScope.launch
{ sharedFlow.collect { } }
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 externalScope.cancel()
externalScope.launch { sharedFlow.collect { } }
Properties Active as long as external scope is alive externalScope.cancel()
externalScope.launch { sharedFlow.collect { } } Complete Exceptionally
Properties Active as long as there are collectors.
Properties Active as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…)
Properties Active as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } }
Properties Active as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } } job.cancel()
Properties Active as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } } job.cancel()
Properties Active as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } } job.cancel()
Properties Active as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) val job1 = launch { sharedFlow.collect { } } val job2 = launch { sharedFlow.collect { } }
Properties Active as long as there are collectors. val sharedFlow
= flow.onCompletion { }.shareIn(…) job1.cancel() val job2 = launch { sharedFlow.collect { } }
Properties Active 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
• Active 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 flow .onStart { println("ON START") }
.shareIn( ... started = SharingStarted.Eagerly)
Eagerly Start producer eagerly flow .onStart { println("ON START") }
.shareIn( ... started = SharingStarted.Eagerly)
Eagerly Start producer eagerly flow .onStart { println("ON START") }
.shareIn( ... started = SharingStarted.Eagerly) // ON START
Eagerly Start producer eagerly
Sharing Policies • While Subscribed • Eagerly • Lazily
Lazily Start sharing after the first subscriber appears
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 Start sharing after the first subscriber appears
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
Manage Backpressure
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 &
Shared Flow APIs • Migrating from broadcast channels • Flow Sharing Strategies • Manage Backpressure
Thank You! www.codingwithmohit.com @heyitsmohit