flowOn

fun <T> Flow<T>.flowOn(context: CoroutineContext): Flow<T>(source)

Changes the context where this flow is executed to the given context. This operator is composable and affects only preceding operators that do not have its own context. This operator is context preserving: context does not leak into the downstream flow.

For example:

withContext(Dispatchers.Main) {
val singleValue = intFlow // will be executed on IO if context wasn't specified before
.map { ... } // Will be executed in IO
.flowOn(Dispatchers.IO)
.filter { ... } // Will be executed in Default
.flowOn(Dispatchers.Default)
.single() // Will be executed in the Main
}

For more explanation of context preservation please refer to Flow documentation.

This operator retains the sequential nature of the flow as long as the context change does not involve changing the dispatcher. However, if the dispatcher is changed, the flow's emissions are performed in a coroutine running with the specified context, and the values are collected in another coroutine using the original collector's context. In this case, a channel with a default buffer size is used internally between the two coroutines, similar to the behavior of the buffer operator. If a buffer operator is explicitly called before or after flowOn, it overrides the default buffering behavior and determines the channel size explicitly.

Note, that flows operating across different dispatchers might lose some in-flight elements when cancelled. In particular, this operator ensures that downstream flow does not resume on cancellation even if the element was already emitted by the upstream flow.

Operator fusion

Adjacent applications of channelFlow, flowOn, buffer, and produceIn are always fused so that only one properly configured channel is used for execution.

Multiple flowOn operators fuse to a single flowOn with a combined context. The elements of the context of the first flowOn operator naturally take precedence over the elements of the second flowOn operator when they have the same context keys, for example:

flow.map { ... } // Will be executed in IO
.flowOn(Dispatchers.IO) // This one takes precedence
.flowOn(Dispatchers.Default)

Note that an instance of SharedFlow does not have an execution context by itself, so applying flowOn to a SharedFlow has not effect. See the SharedFlow documentation on Operator Fusion.

Throws

if provided context contains Job instance.