Milad
Milad

Reputation: 997

The main difference between SharedFlow and StateFlow

What are the differences between SharedFlow and StateFlow?

And how to use these in MVI architecture? is it better to use simple Flow or these as states and events?

Upvotes: 69

Views: 32050

Answers (5)

Dipu Varma
Dipu Varma

Reputation: 1

The main difference between SharedFlow and StateFlow is how they work with data emission and state management in Kotlin's flow API.

  1. StateFlow is used for holding a single updatable state. It always have a current value, and if you update the value, it replace the old one. StateFlow is like LiveData in Android, it always hold the latest state and emit that when new subscriber come.

  2. SharedFlow is more like a broadcast mechanism. It don't hold any value. It is used to emit event or multiple values to many subscribers. SharedFlow is hot flow, so it keeps running even if there is no collector. And you can config it with replay, buffer size etc.

For example:

  • Use StateFlow - when you need to hold UI state, like screen data, because it always have latest value.
  • Use SharedFlow for one-time event, like showing Toast or navigation action.

Upvotes: 0

Pratik Tiwari
Pratik Tiwari

Reputation: 1012

Flow is cold!, means it emits data only when it is collected. Also Flow cannot hold data, take it as a pipe in which water is flowing , data in flow only flows , not stored(no .value function).

Unlike Flow, StateFlow and SharedFlow are hot streams means they emit data even when there is no collector. Also if there are multiple collectors, a new Flow will be run for each collector, completely independent from each other. SharedFlow and StateFlow are Flows that allow for sharing itself between multiple collectors, so that only one flow is effectively run for all of the simultaneous collectors. If you define a SharedFlow that accesses databases and it is collected by multiple collectors, the database access will only run once, and the resulting data will be shared to all collectors.

What are the differences between SharedFlow and StateFlow?

StateFlow

Stateflow takes an initial value through constructor and emits it immediately when someone starts collecting. It gives the latest value to a subscriber even if multiple values are emitted from the flow in quick succession. So if you are collecting in a collector like so:

val stateFlow = MutableStateFlow(0)

val collector = launch {
    val value = stateFlow.value
    println("Received: $value")
}

Say in some other part of the code the stateFlow gets the value 1, 2, 3 in rapid succession the println statement will print 3 when the collector runs if between the time the corouritine took to ran and reading of the value, all the values were already posted.

Stateflow is almost identical to LiveData. LiveData automatically unregisters the consumer when the view goes to the STOPPED state. When collecting a StateFlow this is not handled automatically , you can use repeatOnLifeCyCle scope if you want to unregister the consumer on STOPPED state.

SharedFlow

StateFlow only emits last known value , whereas SharedFlow can configure how many previous values to be emitted. More precisely it has the capability to hold in the emission channel/buffer values until you are ready to consume them so you might get all of them. Lets take the simplest case when replay = 0, this highlights the most subtle difference: new subscribers don't get any values emitted to previous subscribers.

val sharedFlow = MutableSharedFlow<Int>(replay = 0)
val collector = launch {
    sharedFlow.collect { value ->
        println("Received: $value")
    }
}

With the same example 1,2,3 in rapid succession, you might print all three numbers. This is because shared flow can suspend emissions(done explicitly using emit calls) when the consumer is not ready.

If you want emitting and collecting repeated values , use sharedflow.

Summary

In summary, use StateFlow when you need to manage and share a single state with multiple collectors. Instead, use SharedFlow when you need to share a stream of events among collectors without holding any state.

Upvotes: 88

Shubham Kumar Gupta
Shubham Kumar Gupta

Reputation: 1147

I learned it today after so wrong attempts its from official documentation. Hope it helps!

StateFlow implements SharedFlow !! Yes

  • State flow is a shared flow

  • State flow is a special-purpose, high-performance, and efficient implementation of [SharedFlow] for the narrow,
  • but widely used case of sharing a state. See the [SharedFlow] documentation for the basic rules,
  • constraints, and operators that are applicable to all shared flows.
  • State flow always has an initial value, replays one most recent value to new subscribers, does not buffer any
  • more values, but keeps the last emitted one, and does not support [resetReplayCache][MutableSharedFlow.resetReplayCache].
  • A state flow behaves identically to a shared flow when it is created
  • with the following parameters and the [distinctUntilChanged] operator is applied to it:
MutableStateFlow(initialValue) is a shared flow with the following parameters:
  val shared = MutableSharedFlow(
      replay = 1,
      onBufferOverflow = BufferOverflow.DROP_OLDEST
  )
  shared.tryEmit(initialValue) // emit the initial value
  val state = shared.distinctUntilChanged() // get StateFlow-like behavior
  • Use [SharedFlow] when you need a [StateFlow] with tweaks in its behavior such as extra buffering, replaying more
  • values, or omitting the initial value.

Upvotes: -1

Johann
Johann

Reputation: 29885

The main difference between a SharedFlow and a StateFlow is that a StateFlow takes a default value through the constructor and emits it immediately when someone starts collecting, while a SharedFlow takes no value and emits nothing by default.

Upvotes: 16

Tenfour04
Tenfour04

Reputation: 93902

StateFlow is a subtype of SharedFlow that has more restricted configuration options (making it simpler to set up and better performing), but it has the addition of a value property.

StateFlow's value property represents its current value and can be checked from anywhere, including outside of a coroutine. In a MutableStateFlow, you can also emit values from the flow by setting this value property, even from outside any coroutine. MutableSharedFlow has a tryEmit() function that can be used from outside coroutines, but its success when called depends on current state and buffer configuration. On the other hand, setting MutableStateFlow.value always succeeds.

The existence of this concept of a single current value means some of the configurable features of a SharedFlow are not available, because they would break the concept. Here are some of the restrictions:

  1. The replay has to be 1, because there is only 1 current value.
  2. There cannot be any buffer aside from the 1 current value, because there is only 1 value. The one current value cannot be dropped, but old values are always dropped and never seen by a collector if it takes a while to collect the previous value.
  3. It only determines the current value to be changed if you change it to a functionally inequivalent value. This is like enforcing the distinctUntilChanged() operator on a base SharedFlow.
  4. A StateFlow must have an initial value, because it always has a current value. Base SharedFlow doesn't need an initial value.

Hot flows like SharedFlow and StateFlow are useful if your flow logic must monitor something or do IO, and you want to avoid repeating that time-consuming work when there are multiple possible collectors. On Android, it can be used to preserve the flow during a screen rotation, during which collectors might be destroyed and new collectors created to collect the same flow.

Upvotes: 29

Related Questions