- Coroutines are lightweight cooperative concurrent mechanisms.
- They have the ability to pause and resume a function without blocking the thread.
- Blocking a thread is memory-intensive.
- Context switching between threads is expensive.
- During I/O operations, a thread remains idle while waiting for a response.
- The number of threads that can be created depends on available memory.
import kotlinx.coroutines.*
fun main() = runBlocking { // Coroutine builder
launch { // Launch a new coroutine
delay(1000L) // Non-blocking delay
println("World!")
}
println("Hello, ")
}
// Output:
// Hello,
// World!
Defines the lifecycle of a coroutine:
- GlobalScope: Lives throughout the application lifecycle.
GlobalScope.launch {
println("Running in GlobalScope")
}
// Output:
// Running in GlobalScope
- CoroutineScope: Custom scope with specific lifecycle.
val myScope = CoroutineScope(Dispatchers.Default)
myScope.launch {
println("Running in custom CoroutineScope")
}
// Output:
// Running in custom CoroutineScope
- lifecycleScope: Tied to the lifecycle of Android components (e.g., Activity, Service).
lifecycleScope.launch {
fetchData()
}
suspend fun fetchData() {
delay(2000) // Simulate network call
println("Data fetched!")
}
// Output:
// Data fetched!
- viewModelScope: Scoped to ViewModel lifecycle in Android.
viewModelScope.launch {
delay(2000) // Simulate network call
println("Data fetched in ViewModel!")
}
// Output:
// Data fetched in ViewModel!
- Scope Cancellation: Cancel all coroutines in a scope.
val scope = CoroutineScope(Dispatchers.IO)
scope.launch {
val child = launch {
println("Child coroutine started")
delay(1000)
println("Child coroutine finished")
}
delay(500)
println("Cancelling scope")
scope.cancel()
}
// Output:
// Child coroutine started
// Cancelling scope
- Custom Scope: Create with
CoroutineScope(Dispatchers.IO + SupervisorJob())
.
- Dispatchers:
Main
: For UI or log-related tasks.IO
: Optimized for network or file operations.Default
: For CPU-intensive tasks.Unconfined
: Starts in the current thread but may switch threads.
launch(Dispatchers.Default) {
println("Default Dispatcher: Running in thread ${Thread.currentThread().name}")
}
// Output:
// Default Dispatcher: Running in thread DefaultDispatcher-worker-1
- Mark a function with
suspend
to indicate it can be paused.
suspend fun doWorld() {
delay(1000L)
println("World!")
}
// Output:
// World!
- Delays a coroutine without blocking the thread.
- Fire-and-forget style coroutine.
runBlocking {
val job = CoroutineScope(Dispatchers.IO).launch {
println("Coroutine launched")
}
job.join()
}
// Output:
// Coroutine launched
- Coroutine that returns a result.
suspend fun computeSomething(): Int {
delay(500)
return 42
}
runBlocking {
val result = CoroutineScope(Dispatchers.IO).async {
computeSomething()
}
println("Result: ${result.await()}")
}
// Output:
// Result: 42
- Used for switching contexts within a coroutine.
- It runs in suspending way. It waits for children coroutines, to finish.
- Generally used to update UI data from coroutines.
- https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
suspend fun fetchData(): String = withContext(Dispatchers.IO) {
delay(1000)
"Data fetched!"
}
runBlocking {
println(fetchData())
}
// Output:
// Data fetched!
- Creates a coroutine and blocks the thread until completion.
- https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
runBlocking {
println("Running a blocking coroutine")
}
// Output:
// Running a blocking coroutine
- Similar to
runBlocking
, but does not block the thread. - https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
suspend fun fetchData() = coroutineScope {
launch {
delay(1000L)
println("Fetching User Data")
}
launch {
delay(500L)
println("Fetching Posts Data")
}
}
runBlocking {
fetchData()
}
// Output:
// Fetching Posts Data
// Fetching User Data
Ensures that parent and child coroutines follow a defined lifecycle.
- It's a builder paradigm.
Start - run - complete
should be in order.
suspend fun fetchData() = coroutineScope {
launch {
delay(1000L)
println("Fetching User Data")
}
launch {
delay(500L)
println("Fetching Posts Data")
}
}
runBlocking {
fetchData()
println("All data fetched!")
}
// Output:
// Fetching Posts Data
// Fetching User Data
// All data fetched!