flowOn

@ExperimentalCoroutinesApi 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 operators retains a sequential nature of flow if changing the context does not call for changing the dispatcher. Otherwise, if changing dispatcher is required, it collects flow emissions in one coroutine that is run using a specified context and emits them from another coroutines with the original collector’s context using a channel with a default buffer size between two coroutines similarly to buffer operator, unless buffer operator is explicitly called before or after flowOn, which requests buffering behavior and specifies channel size.

Operator fusion

Adjacent applications of channelFlow, flowOn, buffer, produceIn, and broadcastIn 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)

Exceptions

IllegalArgumentException - if provided context contains Job instance.