16

Hey I am learning flow in kotlin. I am learning about MutableStateFlow and MutableSharedFlow. I tried to learn MutableStateFlow in real world example. But I am unable to get the MutableSharedFlow example, which place it suits more. I tried some MutableStateFlow

For example when we are fetching data from api we can use seal class to populate accordingly .

LoggedState.kt

sealed class LoggedState {
    data class OnSuccess(val data: List<XYZ>) : LoggedState()
    object OnEmpty : LoggedState()
    data class IsLoading(val isLoading: Boolean = true) : LoggedState()
    data class OnError(val message: String) : LoggedState()
} 

SettingsViewModel.kt

class SettingsViewModel : ViewModel() {

 var loggedMutableStateFlow = MutableStateFlow<LoggedState>(LoggedState.OnEmpty)

 fun fetchData(){
   val result = dataRepository.getLogged()
                result.handleResult(
                    onSuccess = { response ->
                        val data = response?.items
                        if (!data.isNullOrEmpty()) {
                            loggedMutableStateFlow.value = LoggedState.OnSuccess(data)
                        } else {
                            loggedMutableStateFlow.value = LoggedState.OnEmpty
                        }
                    },
                    onError = {
                        loggedMutableStateFlow.value = LoggedState.OnError(it.message)
                    }
                )
 }

}

Activit.kt

lifecycleScope.launchWhenCreated {
            repeatOnLifecycle(Lifecycle.State.CREATED) {
                viewModel.loggedMutableStateFlow.collect { state ->
                    when (state) {
                        is LoggedState.OnEmpty -> {
                           // view gone
                        }
                        is LoggedState.OnSuccess -> {
                            // show ui
                        }
                        is LoggedState.IsLoading -> {
                            // show spinner
                        }
                        is LoggedState.OnError-> {
                            // show error message
                        }
                    }
                }
            }
        }

I all get the MutableStateFlow example. Can someone guide me how to do MutableSharedFlow in real world examples. Also I am curious about parameters

  1. replay

  2. extraBufferCapacity

  3. onBufferOverflow

Thanks

Kotlin Learner
  • 3,995
  • 6
  • 47
  • 127

2 Answers2

15

StateFlow

StateFlow represents a value that changes and you can listen to those changes as a flow. StateFlow is usually used to represent the state of something in your app, like say the text that should be shown in a TextView. StateFlow is similar to LiveData in android or Subjects in reactive streams.

SharedFlow

SharedFlow represents a stream of values and it can be listened to multiple times just like StateFlow. But it doesn't really have a "current" value (it can have a buffer though). SharedFlow has an arbitrary size buffer that you can configure. SharedFlow is similar to Processor in reactive streams.

Why use it?

SharedFlow's use is more general but it can be used for example to represent button touch events. Since since button touches don't have a "current" value and are really just events in time, SharedFlow would be more appropriate. Another example is a stream of audio data going to a speaker.

Parameters

replay : This is number of events from the buffer the SharedFlow will emit to new subscribers.

extraBufferCapacity : This is the number of events in the buffer the SharedFlow will not emit to new subscribers.

The total buffer size is replay + extraBufferCapacity. Default is 0 for both. Typically you want one or the other but you can use both.

onBufferOverflow: represents what happens when the buffer is full and you try to use emit. There are three possible options for BufferOverflow:

  • SUSPEND: This will make emit suspend until there's space in the buffer. This is the default.

  • DROP_LATEST: This will drop the latest value in the buffer.

  • DROP_OLDEST: This will drop the oldest value in the buffer.

Since the default buffer is zero and overflow strategy is suspend, emit will always suspend with the default parameters.

Relationship with StateFlow

StateFlow is a SharedFlow but SharedFlow is more general than StateFlow. StateFlow is kind of like a SharedFlow with replay buffer size 1. But with StateFlow you can additionally read and write to that value easily with property accessor syntax like this:

stateFlow.value = "hello"
val text = stateFlow.value

Usage

You listen SharedFlow to the same way you do StateFlow albeit with some caveats when it comes to buffers. To send values to a SharedFlow you can use emit from a suspend function or the best effort tryEmit from a non suspend function.

Note that tryEmit will never emit a value with the default parameters since the buffer is zero. It will only really work properly in cases where you know the buffer is non zero and the overflow strategy is not SUSPEND.

A reasonable use case for shared flow is to send button presses to a view model like this:

class WeatherViewModel {
    val refreshEvents = MutableSharedFlow<Unit>(
        extraBufferCapacity = 1, 
        onBufferOverflow = BufferOverflow.DROP_OLDEST
    )
}


fun onButtonPress() {
    refreshEvents.tryEmit(Unit)
}

In practice it's probably better to use an intermediate callbackFlow rather than do it this way.

Ajmal Kunnummal
  • 1,230
  • 10
  • 16
4

MutableStateFlow is similar to MutableLiveData, both have .value to access the value or to change the value.

MutableSharedFlow is similar to SingleLiveEvent, used for observing instant-state changes.

More example and tutorial you can check out this video: https://youtu.be/6Jc6-INantQ

Sam Chen
  • 7,597
  • 2
  • 40
  • 73
  • I tried this video earlier, I want more real example to fit `MutableSharedFlow` – Kotlin Learner Feb 10 '22 at 17:51
  • SharedFlow is only analogous to SingleLiveEvent if you set the `replay` to 0. – Tenfour04 Feb 11 '22 at 01:15
  • SharedFlow(replay = 0) will continue to emit event, when the UI is in background(ie: when no collector available). So those events will be lost even after UI comes to foreground. Here is a reference to use shared flow similar to SingleLiveEvent https://github.com/Kotlin/kotlinx.coroutines/issues/3002#issue-1038122202 – Karthikeyan May 20 '23 at 03:58