Real World Example

Instagram-style Photo Upload

Before uploading a photo, the app reads the file (I/O), compresses it (CPU) and then shows progress on screen (Main). Each step runs on the right dispatcher.

Main  : user taps "Share"
  └─ withContext(IO)      read bytes from disk
  └─ withContext(Default) resize + compress
  └─ withContext(IO)      upload to server
Main  : show "Posted!"

Code

Example

The Main dispatcher does not exist in a console app, so runBlocking's thread plays its role here.

import kotlinx.coroutines.*

class PhotoUploader(
    private val io: CoroutineDispatcher = Dispatchers.IO,
    private val cpu: CoroutineDispatcher = Dispatchers.Default,
) {
    private suspend fun readBytes(path: String): ByteArray = withContext(io) {
        delay(50)
        ByteArray(4_000_000) { (it % 256).toByte() }    // 4 MB photo
    }

    private suspend fun compress(bytes: ByteArray): ByteArray = withContext(cpu) {
        bytes.filterIndexed { i, _ -> i % 8 == 0 }.toByteArray()   // pretend JPEG compression
    }

    private suspend fun upload(bytes: ByteArray): String = withContext(io) {
        delay(100)
        "https://cdn.example.com/p/abc123.jpg (${bytes.size / 1000} KB)"
    }

    suspend fun share(path: String): String {
        val raw = readBytes(path)
        println("Read ${raw.size / 1000} KB")
        val small = compress(raw)
        println("Compressed to ${small.size / 1000} KB")
        return upload(small)
    }
}

fun main() = runBlocking {
    val url = PhotoUploader().share("/sdcard/DCIM/beach.jpg")
    println("Posted: $url")
}

Output

Read 4000 KB
Compressed to 500 KB
Posted: https://cdn.example.com/p/abc123.jpg (500 KB)