Kotlin Coroutines – A Complete Guide
What are Coroutines? Coroutines are a lightweight thread-like mechanism that allows you to perform
asynchronous programming in Kotlin without blocking the main thread. They help you write code that is
non-blocking, concurrent, and easier to manage.
Why use Coroutines? - Avoid callback hell - Perform long-running tasks without freezing the UI - Easy
to write, maintain, and understand - Integrated with Kotlin language and libraries like kotlinx.coroutines
Coroutine Basics
Coroutine Builders: - launch : Starts a new coroutine and doesn't return a result - async : Starts a
new coroutine and returns a deferred result - runBlocking : Runs a coroutine and blocks the current
thread until it completes
Example – Launch:
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
Output:
Hello,
World!
Example – Async / Await:
import kotlinx.coroutines.*
fun main() = runBlocking {
val deferred = async {
delay(1000L)
"Hello from async"
}
println("Waiting for result...")
val result = deferred.await()
println(result)
}
1
Output:
Waiting for result...
Hello from async
Coroutine Context: Coroutine context defines: - Dispatcher (which thread it runs on) - Job - Exception
handler
Dispatchers: - Dispatchers.Main : Runs on the UI thread - Dispatchers.IO : For I/O operations
like file, network - Dispatchers.Default : CPU intensive tasks - Dispatchers.Unconfined : Starts
in current thread, later switches
Example of Dispatcher:
launch(Dispatchers.IO) {
// Background task
}
Structured Concurrency:
fun main() = runBlocking {
coroutineScope {
launch {
delay(500L)
println("Task in coroutineScope")
}
}
println("Coroutine scope is over")
}
Exception Handling:
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
GlobalScope.launch(handler) {
throw AssertionError("Error in coroutine!")
}
Cancellation:
val job = GlobalScope.launch {
repeat(1000) { i ->
2
println("Job is running $i ...")
delay(500L)
}
}
runBlocking {
delay(1300L)
println("Cancelling job")
job.cancel()
job.join()
println("Job cancelled")
}
Important Functions: - delay(timeMillis: Long) : Non-blocking sleep -
withContext(context) { ... } : Switch context - coroutineScope { ... } : Create a scope -
supervisorScope { ... } : Handle failures gracefully
Best Practices: - Use viewModelScope in Android apps - Avoid GlobalScope unless for top-level
tasks - Handle exceptions properly - Always cancel jobs when no longer needed - Prefer launch for
fire-and-forget tasks, async when result is needed
Resources: - Official documentation - kotlinx.coroutines library - Android's architecture
components support coroutines natively