Lessons
Coroutines: suspend, launch, and async/await
suspend keyword, runBlocking, launch (fire-and-forget), async/await (Deferred<T>), delay vs Thread.sleep, and sequential vs concurrent execution.
What to look for:
- suspend: the function can pause without blocking the thread — only callable from coroutine or suspend fn
- delay(ms) suspends the coroutine; Thread.sleep(ms) blocks the OS thread — never use sleep in coroutines
- async {} returns Deferred<T>; .await() suspends until the result is ready
- Two async {} blocks run concurrently — both start before either await() is called
Structured concurrency and CoroutineScope
CoroutineScope lifecycle, Dispatchers (Main, IO, Default), withContext, SupervisorJob, CancellationException, and coroutineScope {} builder.
Prerequisite: Lesson 1
What to look for:
- Cancel the scope when the component is destroyed — all child coroutines are cancelled automatically
- withContext(Dispatchers.IO) { } switches threads for blocking I/O — most common Android pattern
- Always re-throw CancellationException — catching it without rethrowing breaks cancellation
- SupervisorJob: one child failing doesn't cancel siblings — use in ViewModels
Flow: cold streams, operators, and StateFlow
flow {} builder, emit, collect, filter/map/transform operators, cold vs hot flows, StateFlow for UI state, SharedFlow for events.
Prerequisite: Lesson 2
What to look for:
- Flow is cold — the producer code only runs when there's a collector
- StateFlow always has a current value and replays it to new collectors — use for UI state
- SharedFlow has no initial value — use for one-shot events (navigation, toast messages)
- collectLatest: cancels current collector block when new value arrives — ideal for search debounce
Type-safe DSL builders
Lambda with receiver (T.() -> Unit), @DslMarker annotation, building HTML/configuration DSLs, and the apply-based builder pattern.
Prerequisite: Practitioner Track
What to look for:
- fun buildHtml(init: HtmlBuilder.() -> Unit): HtmlBuilder — lambda with receiver enables DSL syntax
- Inside the lambda, this is the receiver object — access its methods without qualification
- @DslMarker prevents implicit receivers from outer scopes leaking into inner builders
- Kotlin's Gradle DSL, Ktor routing, Compose — all built with this pattern
Kotlin Multiplatform basics
KMP project structure, expect/actual declarations, shared vs platform-specific code, common business logic, and the road to full-stack Kotlin.
Prerequisite: Lessons 1–4
What to look for:
- expect/actual: declare an API in shared code, implement per platform — iOS uses Swift interop
- commonMain: shared logic (models, ViewModels, use cases); androidMain/iosMain: platform UI
- Coroutines, collections, and serialisation all have multiplatform support
- Ktor and kotlinx.serialization are the most common KMP server/serialisation libraries
After this track: You have full Kotlin fluency. Good next steps: build an Android app with Jetpack Compose + ViewModel + StateFlow, a server-side API with Ktor, or a Kotlin Multiplatform project sharing logic between Android and iOS. The Kotlin coroutines guide is the authoritative deep reference.
Track quiz
4 questions to check your understanding.
What is the difference between delay() and Thread.sleep() in a coroutine?
What is a cold Flow?
What is expect/actual in Kotlin Multiplatform?
Why should you always re-throw CancellationException?