stateIn

fun <T> Flow<T>.stateIn(scope: CoroutineScope, started: SharingStarted, initialValue: T): StateFlow<T>

Converts a coldFlow into a hotStateFlow that is started in the given coroutine scope, sharing the most recently emitted value from a single running instance of the upstream flow with multiple downstream subscribers. See the StateFlow documentation for the general concepts of state flows.

The starting of the sharing coroutine is controlled by the started parameter, as explained in the documentation for shareIn operator.

The stateIn operator is useful in situations when there is a cold flow that provides updates to the value of some state and is expensive to create and/or to maintain, but there are multiple subscribers that need to collect the most recent state value. For example, consider a flow of state updates coming from a backend over the expensive network connection, taking a lot of time to establish. Conceptually it might be implemented like this:

val backendState: Flow<State> = flow {
connectToBackend() // takes a lot of time
try {
while (true) {
emit(receiveStateUpdateFromBackend())
}
} finally {
disconnectFromBackend()
}
}

If this flow is directly used in the application, then every time it is collected a fresh connection is established, and it will take a while before state updates start flowing. However, we can share a single connection and establish it eagerly like this:

val state: StateFlow<State> = backendMessages.stateIn(scope, SharingStarted.Eagerly, State.LOADING)

Now, a single connection is shared between all collectors from state, and there is a chance that the connection is already established by the time it is needed.

Upstream completion and error handling

Normal completion of the upstream flow has no effect on subscribers, and the sharing coroutine continues to run. If a a strategy like SharingStarted.WhileSubscribed is used, then the upstream can get restarted again. If a special action on upstream completion is needed, then an onCompletion operator can be used before the stateIn operator to emit a special value in this case. See the shareIn operator's documentation for an example.

Any exception in the upstream flow terminates the sharing coroutine without affecting any of the subscribers, and will be handled by the scope in which the sharing coroutine is launched. Custom exception handling can be configured by using the catch or retry operators before the stateIn operator, similarly to the shareIn operator.

Operator fusion

Application of flowOn, conflate, buffer with CONFLATED or RENDEZVOUS capacity, distinctUntilChanged, or cancellable operators to a state flow has no effect.

Parameters

scope

the coroutine scope in which sharing is started.

started

the strategy that controls when sharing is started and stopped.

initialValue

the initial value of the state flow. This value is also used when the state flow is reset using the SharingStarted.WhileSubscribed strategy with the replayExpirationMillis parameter.

suspend fun <T> Flow<T>.stateIn(scope: CoroutineScope): StateFlow<T>

Starts the upstream flow in a given scope, suspends until the first value is emitted, and returns a hotStateFlow of future emissions, sharing the most recently emitted value from this running instance of the upstream flow with multiple downstream subscribers. See the StateFlow documentation for the general concepts of state flows.

Parameters

scope

the coroutine scope in which sharing is started.