Middle
How can you switch threads in Flow? On which thread does Flow operate?
sobes.tech AI
Answer from AI
By default, Flow operates on the thread it was launched on. You can switch threads using the flowOn operator.
import kotlinx.coroutines.CoroutineDispatcher // For CoroutineDispatcher
import kotlinx.coroutines.Dispatchers // For Dispatchers
import kotlinx.coroutines.flow.Flow // For Flow
import kotlinx.coroutines.flow.flow // For flow
import kotlinx.coroutines.flow.flowOn // For flowOn
import kotlinx.coroutines.runBlocking // For runBlocking
// Example of a function returning a Flow
fun simpleFlow(): Flow<Int> = flow {
logThread("Flow started") // Log the thread where flow builder runs
for (i in 1..3) {
emit(i) // Emit values
}
}
fun main() = runBlocking {
simpleFlow()
.flowOn(Dispatchers.IO) // Switch upstream (emitters) to Dispatchers.IO
.collect { value ->
logThread("Collected $value") // Log the thread where values are collected
}
}
// Helper function for logging thread info
fun logThread(msg: String) {
println("[$msg] [${Thread.currentThread().name}]")
}
The flowOn operator affects the thread where upstream operators (including the flow builder) run. Operators after flowOn run on the thread specified in its argument. Multiple flowOn operators affect different parts of the chain.
Example with multiple flowOn:
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
fun simpleFlowWithMultipleFlowOn(): Flow<String> = flow {
logThread("Flow builder started") // Will run on the last specified flowOn before it
emit("A")
emit("B")
}.map {
logThread("Mapping $it") // Will run on the second specified flowOn
it.toLowerCase()
}.flowOn(Dispatchers.Default) // Second flowOn affects map() and flow builder
.filter {
logThread("Filtering $it") // Will run on the thread where collect() is called (default main/runBlocking)
true
}.flowOn(Dispatchers.IO) // First flowOn affects map() and flow builder
fun main() = runBlocking {
simpleFlowWithMultipleFlowOn().collect { value ->
logThread("Collecting $value") // Runs on runBlocking thread (main)
}
}
fun logThread(msg: String) {
println("[$msg] [${Thread.currentThread().name}]")
}
In this example:
flowbuilder andmaprun onDispatchers.Default(the lastflowOnbefore them in the chain).filterruns on the thread wherecollectis called (usually main thread).
Understanding flowOn is crucial for thread management in Kotlin Flow pipelines. It creates an intermediate buffer and does not act as a transparent thread switch.