Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Migrating to Kotlin State & Shared Flows

Migrating to Kotlin State & Shared Flows

Mohit S

June 03, 2022
Tweet

More Decks by Mohit S

Other Decks in Programming

Transcript

  1. Migrating to Kotlin State & Shared Flows • State &

    Shared Flow APIs • Migrating from broadcast channels • Flow Sharing Strategies • Manage Backpressure
  2. What is a cold stream? • Flow completes • Triggers

    same code for every new subscriber
  3. Cold Flows val flow = flowOf(1, 2, 3) 
 .map

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

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

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

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

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

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

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

    { it + 1 } flow.collect { ... } flow.collect { // 2, 3, 4 }
  11. What is a hot stream? • Never completes normally •

    Exists independently of subscribers.
  12. State Flow sealed class UiState { 
 object Loading: UiState()

    
 data class Success(…): UiState() data class Error(…): UiState() }
  13. State Flow sealed class UiState { 
 object Loading: UiState()

    
 data class Success(…): UiState() data class Error(…): UiState() }
  14. State Flow sealed class UiState { 
 object Loading: UiState()

    
 data class Success(…): UiState() data class Error(…): UiState() }
  15. State Flow val stateFlow = MutableStateFlow( . .. ) stateFlow.collect

    { .. . } 
 
 stateFlow.collect { .. . } Latest value is received
  16. State Flow Conflation val stateFlow = MutableStateFlow( . .. )

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

    stateFlow.value = UIState.Success( ... ) 
 
 stateFlow.value = UIState.Error( .. . ) 
 
 stateFlow.collect { .. . } Error
  18. val stateFlow = MutableStateFlow(UIState.Loading) 
 flow1.combine(flow2) { a, b -

    > combineItems(a, b) }.collect { stateFlow.emit(it) } State Flow
  19. Presenter @Composable 
 fun Presenter(eventFlow: Flow<Event>): UiState { 
 val

    event by eventFlow.collectAsState(null) return if (event = = null) { UiState.Loading } else { UiState.Data(…) } }
  20. Presenter @Composable 
 fun Presenter(eventFlow: Flow<Event>): UiState { 
 val

    event by eventFlow.collectAsState(null) return if (event = = null) { UiState.Loading } else { UiState.Data(…) } }
  21. Presenter @Composable 
 fun Presenter(eventFlow: Flow<Event>): UiState { 
 val

    event by eventFlow.collectAsState(null) return if (event = = null) { UiState.Loading } else { UiState.Data(…) } }
  22. View Model class MyViewModel: ViewModel() { 
 
 val stateFlow

    = moleculeScope.launchMolecule { val event by eventFlow.collectAsState(null) return if (event == null) { UiState.Loading } else { UiState.Success(…) } }
  23. Shared Flow val flow = MutableSharedFlow<String>() 
 launch { delay(2000);

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

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

    flow.collect { } } No value is received launch { flow.emit("Event 1”) }
  26. Shared Flow val flow = MutableSharedFlow<String>(replay = 1) 
 launch

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

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

    does not complete normally launch { flow.collect { } }
  29. Cold Flows val flow = flowOf(1, 2, 3) 
 flow

    .onCompletion { } .collect { ... } Flow completes normally
  30. Shared Flow val flow = MutableSharedFlow<String>(replay = 1) val job

    = launch { flow.onCompletion { }.collect { } } job.cancel() Flow completes exceptionally
  31. Properties • Active as long as external scope is alive

    • Remains as long as there are collectors.
  32. Properties Active as long as external scope is alive externalScope.cancel()

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

    externalScope.launch { sharedFlow.collect { } } Complete Exceptionally
  34. Properties Active as long as there are collectors. val sharedFlow

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

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

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

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

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

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

    = flow.onCompletion { }.shareIn(…) job1.cancel() val job2 = launch { sharedFlow.collect { } } Remain Active
  41. Properties • Active as long as external scope is alive

    • Active as long as there are collectors.
  42. Eagerly Start producer eagerly flow .onStart { println("ON START") }

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

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

    .shareIn( ... started = SharingStarted.Eagerly) // ON START
  45. 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
  46. Buffering Overflow Strategies val flow = MutableSharedFlow<String>( extraBufferCapacity = 2,

    onBufferOverflow = BufferOverflow.SUSPEND ) Buffer + Replay Count
  47. Kotlin State & Shared Flows in Action • State &

    Shared Flow APIs • Migrating from broadcast channels • Flow Sharing Strategies • Manage Backpressure