Slide 1

Slide 1 text

Mohit Sarveiya Kotlin State & Shared Flows in Action @heyitsmohit

Slide 2

Slide 2 text

Kotlin State & Shared Flows in Action ● State Flow ● Shared Flow ● Broadcast Channel vs shared flow ● Convert cold streams to shared flows ● Buffer Overflow Strategies

Slide 3

Slide 3 text

Cold vs Hot Flows

Slide 4

Slide 4 text

What is a cold stream? A cold stream is a flow that triggers the same code every time it is collected.

Slide 5

Slide 5 text

Cold Flows val flow = flowOf(1, 2, 3) 
 .map { it + 1 }

Slide 6

Slide 6 text

Cold Flows val flow = flowOf(1, 2, 3) 
 .map { it + 1 } flow.collect { ... }

Slide 7

Slide 7 text

Cold Flows val flow = flowOf(1, 2, 3) 
 .map { it + 1 } flow.collect { ... }

Slide 8

Slide 8 text

Cold Flows val flow = flowOf(1, 2, 3) 
 .map { it + 1 } flow.collect { ... }

Slide 9

Slide 9 text

Cold Flows val flow = flowOf(1, 2, 3) 
 .map { it + 1 } flow.collect { // 2, 3, 4 }

Slide 10

Slide 10 text

Cold Flows val flow = flowOf(1, 2, 3) 
 .map { it + 1 } flow.collect { ... } flow.collect { ... }

Slide 11

Slide 11 text

Cold Flows val flow = flowOf(1, 2, 3) 
 .map { it + 1 } flow.collect { ... } flow.collect { ... }

Slide 12

Slide 12 text

Cold Flows val flow = flowOf(1, 2, 3) 
 .map { it + 1 } flow.collect { ... } flow.collect { // 2, 3, 4 }

Slide 13

Slide 13 text

What is a hot stream? A hot stream is a flow whose active instance exists independently 
 of the presence of collectors.

Slide 14

Slide 14 text

Hot Streams State Flow Shared Flow

Slide 15

Slide 15 text

State Flow View View Model

Slide 16

Slide 16 text

State Flow View View Model

Slide 17

Slide 17 text

State Flow View View Model State

Slide 18

Slide 18 text

State Flow sealed class UiState { 
 data class Error( 
 val exception: Throwable 
 ): UiState() }

Slide 19

Slide 19 text

State Flow sealed class UiState { 
 data class Success( val data: Data ): UiState() data class Error( 
 val exception: Throwable 
 ): UiState() }

Slide 20

Slide 20 text

State Flow sealed class UiState { 
 data class Success( val data: Data ): UiState() data class Error( 
 val exception: Throwable 
 ): UiState() }

Slide 21

Slide 21 text

State Flow val uiState = MutableStateFlow()

Slide 22

Slide 22 text

val uiState = MutableStateFlow( UiState.Success(Data()) ) State Flow

Slide 23

Slide 23 text

State Flow val uiState = MutableStateFlow( . .. ) uiState.emit( 
 UIState.Success(Data()) 
 )

Slide 24

Slide 24 text

State Flow val uiState = MutableStateFlow( . .. ) uiState.value = UIState.Success(Data()) 


Slide 25

Slide 25 text

State Flow val uiState = MutableStateFlow( . .. ) uiState.collect { ... } 
 Latest value is received

Slide 26

Slide 26 text

State Flow val uiState = MutableStateFlow( . .. ) uiState.collect { ... } 
 
 uiState.collect { ... } Latest value is received

Slide 27

Slide 27 text

State Flow Conflation val uiState = MutableStateFlow( . .. ) uiState.value = UIState.Success( .. . ) 
 
 uiState.value = UIState.Error( .. . ) Conflate

Slide 28

Slide 28 text

State Flow Conflation val uiState = MutableStateFlow( . .. ) uiState.value = UIState.Success( .. . ) 
 
 uiState.value = UIState.Error( .. . ) 
 
 uiState.collect { ... } Error

Slide 29

Slide 29 text

State Flow vs Live Data State Flow Live Data Default Value Unsubscribe 
 (Stopped State)

Slide 30

Slide 30 text

State Flow vs Live Data State Flow Live Data Default Value Unsubscribe 
 (Stopped State)

Slide 31

Slide 31 text

State Flow vs Live Data State Flow Live Data Default Value Unsubscribe 
 (Stopped State)

Slide 32

Slide 32 text

State Flow Summary ● How to setup state flow ● Emit and collect ● State Flow vs Live Data

Slide 33

Slide 33 text

Shared Flow

Slide 34

Slide 34 text

Shared Flow

Slide 35

Slide 35 text

Shared Flow Consumer 1 Consumer 2

Slide 36

Slide 36 text

Shared Flow Consumer 1 Consumer 2

Slide 37

Slide 37 text

Shared Flow Consumer 1 Consumer 2 Event Event

Slide 38

Slide 38 text

Shared Flow Consumer 1 Consumer 2 Replay Replay

Slide 39

Slide 39 text


 Shared Flow Buffer

Slide 40

Slide 40 text

Shared Flow val flow = MutableSharedFlow < > ()

Slide 41

Slide 41 text

Shared Flow val flow = MutableSharedFlow()

Slide 42

Slide 42 text

Shared Flow val flow = MutableSharedFlow()

Slide 43

Slide 43 text

Shared Flow val flow = MutableSharedFlow() launch { flow.collect { } }

Slide 44

Slide 44 text

Shared Flow val flow = MutableSharedFlow() 
 launch { flow.emit("Event 1") } launch { flow.collect { } }

Slide 45

Slide 45 text

Shared Flow val flow = MutableSharedFlow() 
 launch { flow.emit("Event 1") } launch { flow.collect { } } Event 1

Slide 46

Slide 46 text

Shared Flow val flow = MutableSharedFlow() 
 launch { flow.emit("Event 1”) } launch { delay(2000); flow.collect { } }

Slide 47

Slide 47 text

Shared Flow val flow = MutableSharedFlow() 
 launch { delay(2000); flow.collect { } } launch { flow.emit("Event 1”) }

Slide 48

Slide 48 text

Shared Flow val flow = MutableSharedFlow() 
 launch { delay(2000); flow.collect { } } launch { flow.emit("Event 1”) }

Slide 49

Slide 49 text

Shared Flow val flow = MutableSharedFlow() 
 launch { delay(2000); flow.collect { } } No value is received launch { flow.emit("Event 1”) }

Slide 50

Slide 50 text

Shared Flow val flow = MutableSharedFlow() 
 launch { flow.emit("Event 1”) } launch { delay(2000); flow.collect { } } Replay

Slide 51

Slide 51 text

Shared Flow val flow = MutableSharedFlow(replay = 1) 
 launch { flow.emit("Event 1”) } launch { delay(2000); flow.collect { } }

Slide 52

Slide 52 text

Shared Flow val flow = MutableSharedFlow(replay = 1) 
 launch { delay(2000); flow.collect { } } launch { flow.emit("Event 1”) } Event 1

Slide 53

Slide 53 text

val flow = MutableSharedFlow(replay = 1) 
 Shared Flow State Flow launch { flow.collect { } } launch { flow.subscriptionCount.value }

Slide 54

Slide 54 text

Shared Flow val flow = MutableSharedFlow(replay = 1) 1 Subscriber launch { flow.collect { } } launch { flow.subscriptionCount.value }

Slide 55

Slide 55 text

Shared Flow val flow = MutableSharedFlow(replay = 1) Shared Flow does not complete normally launch { flow.collect { } }

Slide 56

Slide 56 text

Cold Flows val flow = flowOf(1, 2, 3) 
 flow .onCompletion { } .collect { ... } Flow completes normally

Slide 57

Slide 57 text

Shared Flow val flow = MutableSharedFlow(replay = 1) val job = launch { flow.collect { } } job.cancel()

Slide 58

Slide 58 text

Shared Flow val flow = MutableSharedFlow(replay = 1) val job = launch { flow.onCompletion { }.collect { } } job.cancel() Flow completes exceptionally

Slide 59

Slide 59 text

Shared Flow Summary ● Setup ● Replay and emit ● Cancellation

Slide 60

Slide 60 text

Broadcast Channel vs Shared Flow

Slide 61

Slide 61 text

Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed

Slide 62

Slide 62 text

val channel = BroadcastChannel(10)

Slide 63

Slide 63 text

val channel = BroadcastChannel(10) channel.send( ... )

Slide 64

Slide 64 text

val channel = BroadcastChannel(10) channel.send( ... ) channel.close()

Slide 65

Slide 65 text

val stateFlow = MutableSharedFlow() stateFlow.emit( ... )

Slide 66

Slide 66 text

Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed

Slide 67

Slide 67 text

val stateFlow = MutableSharedFlow(replay = 2) stateFlow.emit( ... )

Slide 68

Slide 68 text

Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed

Slide 69

Slide 69 text

val channel = BroadcastChannel(capacity = 10) channel.send( ... )

Slide 70

Slide 70 text

val stateFlow = MutableSharedFlow( replay = 2, extraBufferCapacity = 10 ) stateFlow.emit( ... )

Slide 71

Slide 71 text

Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed

Slide 72

Slide 72 text

val channel = BroadcastChannel(10) channel.send( ... ) channel.close()

Slide 73

Slide 73 text

val stateFlow = MutableSharedFlow( replay = 2, extraBufferCapacity = 10 ) stateFlow.emit( ... )

Slide 74

Slide 74 text

Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed

Slide 75

Slide 75 text

Broadcast Channel Shared Flow

Slide 76

Slide 76 text

val channel = BroadcastChannel(capacity)

Slide 77

Slide 77 text

val channel = BroadcastChannel(capacity) val flow = MutableSharedFlow(extraBufferCapacity)

Slide 78

Slide 78 text

channel.send( ... ) channel.trySend( ... ) flow.emit( ... ) flow.tryEmit( ... )

Slide 79

Slide 79 text

Broadcast Channel Shared Flow Channel APIs Replay Buffer Closed

Slide 80

Slide 80 text

Flow Sharing Strategies

Slide 81

Slide 81 text

Cold Flow Hot Flow Convert

Slide 82

Slide 82 text

Sharing Policies • While Subscribed • Eagerly • Lazily

Slide 83

Slide 83 text

Sharing Policies flow

Slide 84

Slide 84 text

Sharing Policies flow.shareIn( )

Slide 85

Slide 85 text

Sharing Policies flow.shareIn( externalScope, )

Slide 86

Slide 86 text

Sharing Policies flow.shareIn( externalScope, replay = 1, )

Slide 87

Slide 87 text

Sharing Policies flow.shareIn( externalScope, replay = 1, started = SharingStarted.WhileSubscribed() )

Slide 88

Slide 88 text

Sharing Policies val sharedFlow = flow.shareIn( externalScope, replay = 1, started = SharingStarted.WhileSubscribed() )

Slide 89

Slide 89 text

While Subscribed • Active as long as external scope is alive • Remains as long as there are collectors.

Slide 90

Slide 90 text

Properties Active as long as external scope is alive

Slide 91

Slide 91 text

Properties Active as long as external scope is alive sharedFlow.collect { } Subscriber

Slide 92

Slide 92 text

flow.shareIn( externalScope, replay = 1, started = SharingStarted.WhileSubscribed() ) Properties Active as long as external scope is alive

Slide 93

Slide 93 text

Properties Active as long as external scope is alive sharedFlow.collect { } externalScope.cancel()

Slide 94

Slide 94 text

Properties Active as long as external scope is alive sharedFlow.collect { } externalScope.cancel() Complete Exceptionally

Slide 95

Slide 95 text

Properties Remains as long as there are collectors.

Slide 96

Slide 96 text

Properties Remains as long as there are collectors. val sharedFlow = flow.onCompletion { }.shareIn(…)

Slide 97

Slide 97 text

Properties Remains as long as there are collectors. val sharedFlow = flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } }

Slide 98

Slide 98 text

Properties Remains as long as there are collectors. val sharedFlow = flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } } job.cancel()

Slide 99

Slide 99 text

Properties Remains as long as there are collectors. val sharedFlow = flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } } job.cancel()

Slide 100

Slide 100 text

Properties Remains as long as there are collectors. val sharedFlow = flow.onCompletion { }.shareIn(…) val job = launch { sharedFlow.onCompletion { }.collect { } } job.cancel()

Slide 101

Slide 101 text

Properties Remains as long as there are collectors. val sharedFlow = flow.onCompletion { }.shareIn(…) val job1 = launch { sharedFlow.collect { } } val job2 = launch { sharedFlow.collect { } }

Slide 102

Slide 102 text

Properties Remains as long as there are collectors. val sharedFlow = flow.onCompletion { }.shareIn(…) job1.cancel() val job2 = launch { sharedFlow.collect { } }

Slide 103

Slide 103 text

Properties Remains as long as there are collectors. val sharedFlow = flow.onCompletion { }.shareIn(…) job1.cancel() val job2 = launch { sharedFlow.collect { } } Remain Active

Slide 104

Slide 104 text

Properties • Active as long as external scope is alive • Remains as long as there are collectors.

Slide 105

Slide 105 text

Sharing Policies • While Subscribed • Eagerly • Lazily

Slide 106

Slide 106 text

Eagerly flow.shareIn( externalScope, replay = 1, started = SharingStarted.Eagerly() )

Slide 107

Slide 107 text

Eagerly Start producer eagerly and never stop flow .onStart { println("ON START") } .shareIn( ... started = SharingStarted.Eagerly)

Slide 108

Slide 108 text

Eagerly Start producer eagerly and never stop flow .onStart { println("ON START") } .shareIn( ... started = SharingStarted.Eagerly)

Slide 109

Slide 109 text

Eagerly Start producer eagerly and never stop flow .onStart { println("ON START") } .shareIn( ... started = SharingStarted.Eagerly) ON START

Slide 110

Slide 110 text

Eagerly Start producer eagerly and never stop flow .onComplete { println("ON COMPLETE”) } .shareIn( ... started = SharingStarted.Eagerly)

Slide 111

Slide 111 text

Eagerly Start producer eagerly and never stop flow .onComplete { println("ON COMPLETE”) } .shareIn( ... started = SharingStarted.Eagerly) externalScope.cancel()

Slide 112

Slide 112 text

Eagerly Start producer eagerly and never stop flow .onComplete { println("ON COMPLETE”) } .shareIn( ... started = SharingStarted.Eagerly) Never stops externalScope.cancel()

Slide 113

Slide 113 text

Eagerly Start producer eagerly and never stop

Slide 114

Slide 114 text

Sharing Policies • While Subscribed • Eagerly • Lazily

Slide 115

Slide 115 text

Lazily Start sharing after the first subscriber appears and never stop

Slide 116

Slide 116 text

Lazily flow.shareIn( externalScope, replay = 1, started = SharingStarted.Lazily )

Slide 117

Slide 117 text

Lazily flow .onStart { println("ON START") } .shareIn(…,started = SharingStarted.Lazily)

Slide 118

Slide 118 text

Lazily flow .onStart { println("ON START") } .shareIn(…,started = SharingStarted.Lazily) launch { sharedFlow.collect { } }

Slide 119

Slide 119 text

Lazily flow .onStart { println("ON START") } .shareIn(…,started = SharingStarted.Lazily) launch { sharedFlow.collect { } } "ON START"

Slide 120

Slide 120 text

Lazily flow .onCompletion { println("COMPLETE") } .shareIn(…,started = SharingStarted.Lazily)

Slide 121

Slide 121 text

flow .onCompletion { println("COMPLETE") } .shareIn(externalScope,…,started = SharingStarted.Lazily) Lazily

Slide 122

Slide 122 text

flow .onCompletion { println("COMPLETE") } .shareIn(externalScope,…,started = SharingStarted.Lazily) Lazily externalScope.cancel()

Slide 123

Slide 123 text

flow .onCompletion { println("COMPLETE") } .shareIn(externalScope,…,started = SharingStarted.Lazily) Lazily Never stops externalScope.cancel()

Slide 124

Slide 124 text

Lazily Start sharing after the first subscriber appears and never stop

Slide 125

Slide 125 text

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

Slide 126

Slide 126 text

Buffer Overflow Strategies

Slide 127

Slide 127 text


 Shared Flow Buffer

Slide 128

Slide 128 text


 Shared Flow Producer Consumer

Slide 129

Slide 129 text


 Shared Flow Producer Consumer Generating events fast

Slide 130

Slide 130 text


 Shared Flow Producer Consumer Listening to events 
 with delay

Slide 131

Slide 131 text


 Shared Flow Producer Consumer

Slide 132

Slide 132 text


 Shared Flow Producer Consumer

Slide 133

Slide 133 text


 Shared Flow Producer Consumer What happens when it is full?

Slide 134

Slide 134 text

Buffering Overflow Strategies • Suspend • Drop oldest • Drop latest

Slide 135

Slide 135 text


 Shared Flow Producer Consumer Suspend

Slide 136

Slide 136 text

Buffering Overflow Strategies val flow = MutableSharedFlow( extraBufferCapacity = 2, onBufferOverflow = BufferOverflow.SUSPEND ) Buffer + Replay Count

Slide 137

Slide 137 text

Buffering Overflow Strategies val flow = MutableSharedFlow( extraBufferCapacity = 2, onBufferOverflow = BufferOverflow.SUSPEND )

Slide 138

Slide 138 text

Buffering Overflow Strategies launch { flow.emit("Event 1") flow.emit("Event 2") flow.emit("Event 3") } Suspend

Slide 139

Slide 139 text

Buffering Overflow Strategies • Suspend • Drop oldest • Drop latest

Slide 140

Slide 140 text


 Shared Flow Producer Consumer Drop Oldest

Slide 141

Slide 141 text


 Shared Flow Producer Consumer Drop latest

Slide 142

Slide 142 text

Buffering Overflow Strategies • Suspend • Drop oldest • Drop latest

Slide 143

Slide 143 text

Kotlin State & Shared Flows in Action ● State Flow ● Shared Flow ● Broadcast Channel vs shared flow ● Convert cold streams to shared flows ● Buffer Overflow Strategies

Slide 144

Slide 144 text

https: // codingwithmohit.com/coroutines/learning-shared-and-state-flows-with-tests/ Coding with Mohit

Slide 145

Slide 145 text

Thank You! www.codingwithmohit.com @heyitsmohit