← Kotlin EnglishChapter 11 of 13

Coroutines

## Learning Objectives - Understand coroutines and their benefits - Use suspend functions - Launch coroutines with launch and async - Work with coroutine builders - Manage coroutine scopes and dispatchers ## What are Coroutines? Coroutines are Kotlin's solution for asynchronous programming. They are lightweight threads that can be suspended and resumed. ### vs Threads - Threads are heavy, coroutines are lightweight - Millions of coroutines can run on few threads - Coroutines can be suspended without blocking ```kotlin import kotlinx.coroutines.* fun main() { println("Starting...") // Launch a coroutine GlobalScope.launch { delay(1000) // Non-blocking delay println("Inside coroutine") } println("After launch...") Thread.sleep(2000) // Keep main thread alive println("Done") } ``` ## Suspend Functions `suspend` marks a function that can be paused and resumed: ```kotlin import kotlinx.coroutines.* suspend fun fetchData(): String { delay(1000) // Suspends without blocking return "Data loaded" } fun main() = runBlocking { println("Before") val data = fetchData() println(data) println("After") } ``` ## Coroutine Builders ### launch Fire and forget - doesn't return result: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { delay(1000) println("Task completed") } println("Waiting...") job.join() // Wait for job to complete println("Done") } ``` ### async Returns a result via Deferred: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val deferred = async { delay(1000) "Result" } println("Waiting for result...") val result = deferred.await() println("Result: $result") } ``` ### runBlocking Blocks current thread until coroutines complete: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { launch { delay(500) println("Task 1") } launch { delay(300) println("Task 2") } println("Waiting...") } ``` ## Structured Concurrency ### coroutineScope Creates a scope that waits for all children: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { coroutineScope { launch { delay(1000) println("Task 1") } launch { delay(500) println("Task 2") } } println("All tasks completed") } ``` ### launch in coroutineScope ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { doWork() } suspend fun doWork() = coroutineScope { launch { delay(200) println("Work 1") } launch { delay(100) println("Work 2") } println("Scope started") } ``` ## Dispatchers Control which thread runs the coroutine: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { launch { // Default dispatcher println("Default: ${Thread.currentThread().name}") } launch(Dispatchers.IO) { println("IO: ${Thread.currentThread().name}") } launch(Dispatchers.Default) { println("Default: ${Thread.currentThread().name}") } launch(Dispatchers.Unconfined) { println("Unconfined: ${Thread.currentThread().name}") } } ``` ### With Context ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { launch(Dispatchers.Default) { println("Running in Default dispatcher") } withContext(Dispatchers.IO) { println("Running in IO dispatcher") } } ``` ## Exception Handling ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { try { repeat(1000) { i -> println("Working $i") delay(500) } } finally { println("Cleanup!") } } delay(2000) job.cancelAndJoin() println("Cancelled") } ``` ### withTimeout ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { try { withTimeout(1500) { repeat(1000) { i -> println("Working $i") delay(500) } } } catch (e: TimeoutCancellationException) { println("Timed out!") } } ``` ## Sequential Execution Without coroutines: ```kotlin import kotlinx.coroutines.* import kotlinx.coroutines.experimental.* suspend fun doTask1(): String { delay(1000) return "Task 1" } suspend fun doTask2(): String { delay(1000) return "Task 2" } fun main() = runBlocking { val time = measureTimeMillis { val result1 = doTask1() val result2 = doTask2() println("$result1, $result2") } println("Took ${time}ms") // ~2000ms } ``` With async: ```kotlin fun main() = runBlocking { val time = measureTimeMillis { val result1 = async { doTask1() } val result2 = async { doTask2() } println("${result1.await()}, ${result2.await()}") } println("Took ${time}ms") // ~1000ms } ``` ## Cancellation ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { repeat(1000) { i -> println("Working $i") delay(500) } } delay(2000) println("Cancelling...") job.cancel() job.join() println("Cancelled") } ``` ### isActive Check ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { var i = 0 while (isActive) { // Check if still active println("Working $i") delay(500) i++ } } delay(2000) job.cancelAndJoin() println("Done") } ``` ## Flows Flows are cold asynchronous streams: ```kotlin import kotlinx.coroutines.* import kotlinx.coroutines.flow.* fun main() = runBlocking { // Create a flow val flow = flow { for (i in 1..5) { delay(500) emit(i) } } // Collect flow flow.collect { value -> println("Received: $value") } } ``` ### Flow Operators ```kotlin import kotlinx.coroutines.* import kotlinx.coroutines.flow.* fun main() = runBlocking { (1..5).asFlow() .map { it * it } .filter { it > 5 } .collect { println(it) } } ``` ## Summary - Coroutines are lightweight async building blocks - `suspend` marks functions that can be paused - `launch` for fire-and-forget, `async` for results - `runBlocking` blocks current thread - `Dispatchers.IO`, `Dispatchers.Default`, `Dispatchers.Main` - Structured concurrency with `coroutineScope` - `cancel()` and `withTimeout` for cancellation - Flows are cold asynchronous streams

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →