Careeroza
withContext
Switching Threads Safely
withContext(dispatcher) { } runs a block on another dispatcher, suspends the caller until it finishes, and returns its result. It is the standard way to make a function main-safe: callers can call it from the UI thread without freezing the screen.
class UserRepository(private val dao: UserDao, private val io: CoroutineDispatcher = Dispatchers.IO) {
// main-safe: may be called from Dispatchers.Main
suspend fun loadUser(id: Long): User = withContext(io) {
dao.findById(id) // blocking database call runs on IO
}
}Example
Example
Read on IO, process on Default, then continue on the original thread.
import kotlinx.coroutines.*
fun where() = Thread.currentThread().name.substringBefore("-worker")
suspend fun readCsv(): List<String> = withContext(Dispatchers.IO) {
println("Reading file on ${where()}")
listOf("apple,40", "mango,120", "banana,30", "grapes,90")
}
suspend fun totalPrice(lines: List<String>): Int = withContext(Dispatchers.Default) {
println("Calculating on ${where()}")
lines.sumOf { it.substringAfter(",").toInt() }
}
fun main() = runBlocking {
println("Start on ${where()}")
val lines = readCsv()
val total = totalPrice(lines)
println("Back on ${where()}: total = $total")
}Output
Start on main Reading file on DefaultDispatcher Calculating on DefaultDispatcher Back on main: total = 280
Tips
- Switch dispatchers inside the function that does the blocking work (repository, data source), not in the UI layer.
- Inject the dispatcher as a constructor parameter (
io: CoroutineDispatcher = Dispatchers.IO) so tests can replace it. - Libraries like Room, Retrofit and Ktor already switch threads internally: you can call their suspend functions from
Maindirectly.