๐ 01 ยท learn android
Kotlin Coroutines
Concurrency without the thread-per-task tax
Lightweight threads that make async code read top-to-bottom.
A coroutine is Kotlin's answer to a problem that predates Kotlin: asynchronous work โ a network call, a disk read, a timer โ doesn't fit the synchronous "do this, then this" shape most code is written in. The old ways were callbacks (nested, error-prone) and threads (heavy, expensive, dangerous to coordinate). Coroutines are a third way: a block of code that can pause at a suspension point and resume later, without holding a thread hostage while it waits.
The mental model to hold onto: a coroutine is not a thread. It's a lightweight unit of work that runs on a thread, can be moved between threads, and โ critically โ can suspend, freeing its thread to run something else. You can have thousands of coroutines on a handful of threads, where thousands of threads would collapse under their own weight.
The mental model
How it fits together
Dispatchers โ which thread
Structured concurrency โ the tree
โ
suspend โ resume
await() โ result
cancel the scope โ every child is cancelled
Key concepts
The ideas to internalise
suspend
A suspend function can pause and resume without blocking a thread. It carries a hidden continuation that remembers where it paused and what its locals were.
launch vs async
launch fires a coroutine and forgets it; async fires one and hands back a Deferred you await for a result. Fire-and-forget vs. get-a-result.
Dispatchers
Decide which thread a coroutine runs on โ Main for UI, IO for blocking I/O, Default for CPU-bound work.
Structured concurrency
Work is a tree. Cancel the scope and every child is cancelled; a child's failure is reported to its parent. No orphaned coroutines.
Scopes
viewModelScope and lifecycleScope tie work to a screen's lifetime and auto-cancel it when the screen dies.
Cooperative cancellation
A coroutine checks a cancellation flag at every suspension point. A tight non-suspending loop must call yield() or ensureActive() to be cancellable.
Example index
11 runnable examples
Each is a self-contained Activity + ViewModel pair you can open, read, and run.
- 01Single Network Callthe simplest coroutine network call
- 02Series Network Callstwo calls where the second depends on the first
- 03Parallel Network Callsindependent calls running concurrently via async + awaitAll
- 04Room DB Operationcoroutines with Room
- 05Long Running Taska background task off the main thread
- 06Two Long Running Taskstwo tasks in parallel
- 07TimeoutwithTimeout โ cancelling a task past a deadline
- 08Try-Catch Error Handlingcatching exceptions inside a coroutine
- 09CoroutineExceptionHandlercentralized error handling
- 10Ignore Error & ContinuesupervisorScope โ one failure doesn't kill siblings
- 11Unit Testtesting a coroutine-based ViewModel
The takeaway
Series vs parallel is the same operation with a different structure: withContext back-to-back waits for each call; async + awaitAll runs them together. The choice is simply which structure you write โ and structured concurrency guarantees the tree of work is torn down with its owner.