KtKotlin · Lesson 6 of 8

Coroutines — async Made Simple

Fetch from the network without freezing the UI — the core problem of app development. Coroutines let you write asynchronous code that reads exactly like synchronous code.

Kotlin
import kotlinx.coroutines.*

// 'suspend' marks a function that can pause without
// blocking its thread:
suspend fun fetchUser(): String {
    delay(1000)              // pretend network call (non-blocking)
    return "Ada"
}

suspend fun fetchScore(): Int {
    delay(1000)
    return 95
}

fun main() = runBlocking {
    // Sequential — takes ~2 seconds:
    val user = fetchUser()
    val score = fetchScore()
    println("$user: $score")

    // Concurrent — takes ~1 second:
    val userDeferred = async { fetchUser() }
    val scoreDeferred = async { fetchScore() }
    println("${userDeferred.await()}: ${scoreDeferred.await()}")
}

delay() suspends the coroutine but frees the thread to do other work — unlike Thread.sleep(), which blocks it. launch starts a fire-and-forget coroutine; async starts one that returns a value you await. Structured concurrency means coroutines launched in a scope are cancelled with it — no leaked background work.

Kotlin
// The shape you'll write constantly in Android:
class ProfileViewModel : ViewModel() {
    fun loadProfile() {
        // viewModelScope dies with the screen — auto-cancel:
        viewModelScope.launch {
            val user = withContext(Dispatchers.IO) {
                api.fetchUser()        // network on IO threads
            }
            _uiState.value = UiState.Loaded(user)  // back on main
        }
    }
}

// Dispatchers = which threads:
// Dispatchers.Main    -> UI updates
// Dispatchers.IO      -> network / disk
// Dispatchers.Default -> heavy computation
◆ Note
Compare with JavaScript: suspend fun ≈ async function, await() ≈ await. The big extra is structured concurrency — parents own their children, cancellation propagates, and 'forgotten' background tasks can't outlive the screen that started them.