0
# Coroutine Builders
1
2
Functions for creating and launching coroutines with different execution patterns and result handling. These builders provide the primary means of starting concurrent operations within coroutine scopes.
3
4
## Capabilities
5
6
### Launch Builder
7
8
Fire-and-forget coroutine that returns a Job for lifecycle management.
9
10
```kotlin { .api }
11
/**
12
* Launches a new coroutine without blocking the current thread
13
* @param context additional context elements for the coroutine
14
* @param start coroutine start option (DEFAULT, LAZY, ATOMIC, UNDISPATCHED)
15
* @param block the coroutine code
16
* @return Job representing the coroutine
17
*/
18
fun CoroutineScope.launch(
19
context: CoroutineContext = EmptyCoroutineContext,
20
start: CoroutineStart = CoroutineStart.DEFAULT,
21
block: suspend CoroutineScope.() -> Unit
22
): Job
23
```
24
25
**Usage Examples:**
26
27
```kotlin
28
import kotlinx.coroutines.*
29
30
val scope = CoroutineScope(Dispatchers.Default)
31
32
// Basic launch
33
val job = scope.launch {
34
delay(1000)
35
println("Task completed")
36
}
37
38
// Launch with custom context
39
val jobWithContext = scope.launch(Dispatchers.IO + CoroutineName("file-processor")) {
40
// Runs on IO dispatcher with debug name
41
processFile()
42
}
43
44
// Lazy launch (starts when job.start() is called or join() is awaited)
45
val lazyJob = scope.launch(start = CoroutineStart.LAZY) {
46
expensiveComputation()
47
}
48
lazyJob.start() // Explicitly start the coroutine
49
50
// Wait for completion
51
job.join()
52
```
53
54
### Async Builder
55
56
Concurrent computation that returns a Deferred with a result value.
57
58
```kotlin { .api }
59
/**
60
* Creates a coroutine that computes a value concurrently
61
* @param context additional context elements for the coroutine
62
* @param start coroutine start option
63
* @param block the coroutine code that returns a value
64
* @return Deferred representing the future result
65
*/
66
fun <T> CoroutineScope.async(
67
context: CoroutineContext = EmptyCoroutineContext,
68
start: CoroutineStart = CoroutineStart.DEFAULT,
69
block: suspend CoroutineScope.() -> T
70
): Deferred<T>
71
```
72
73
**Usage Examples:**
74
75
```kotlin
76
import kotlinx.coroutines.*
77
78
suspend fun concurrentComputation() {
79
val scope = CoroutineScope(Dispatchers.Default)
80
81
// Launch multiple async computations
82
val deferred1 = scope.async { computeValue1() }
83
val deferred2 = scope.async { computeValue2() }
84
val deferred3 = scope.async { computeValue3() }
85
86
// Wait for all results
87
val result1 = deferred1.await()
88
val result2 = deferred2.await()
89
val result3 = deferred3.await()
90
91
println("Results: $result1, $result2, $result3")
92
}
93
94
// Async with custom context
95
suspend fun asyncWithContext() = coroutineScope {
96
val networkCall = async(Dispatchers.IO) {
97
fetchDataFromNetwork()
98
}
99
100
val localData = async(Dispatchers.Default) {
101
processLocalData()
102
}
103
104
// Combine results
105
CombinedResult(networkCall.await(), localData.await())
106
}
107
```
108
109
### WithContext
110
111
Context switching function that executes a block in a different context and returns the result.
112
113
```kotlin { .api }
114
/**
115
* Calls the specified block with the given coroutine context
116
* @param context the new context for the block
117
* @param block the code to execute in the new context
118
* @return the result of the block
119
*/
120
suspend fun <T> withContext(
121
context: CoroutineContext,
122
block: suspend CoroutineScope.() -> T
123
): T
124
```
125
126
**Usage Examples:**
127
128
```kotlin
129
import kotlinx.coroutines.*
130
131
suspend fun processData() {
132
// Switch to IO context for file operations
133
val fileContent = withContext(Dispatchers.IO) {
134
readFileContent("data.txt")
135
}
136
137
// Switch to Default context for computation
138
val processedData = withContext(Dispatchers.Default) {
139
heavyProcessing(fileContent)
140
}
141
142
// Switch to Main context for UI updates (if available)
143
withContext(Dispatchers.Main) {
144
updateUI(processedData)
145
}
146
}
147
148
// WithContext with timeout
149
suspend fun fetchWithTimeout() {
150
val result = withContext(Dispatchers.IO) {
151
withTimeout(5000) {
152
fetchDataFromServer()
153
}
154
}
155
return result
156
}
157
```
158
159
### RunBlocking
160
161
Blocking bridge between regular and suspend functions (platform-specific availability).
162
163
```kotlin { .api }
164
/**
165
* Runs a new coroutine and blocks the current thread until completion
166
* @param context the context for the new coroutine
167
* @param block the coroutine code
168
* @return the result of the coroutine
169
*/
170
fun <T> runBlocking(
171
context: CoroutineContext = EmptyCoroutineContext,
172
block: suspend CoroutineScope.() -> T
173
): T
174
```
175
176
**Usage Examples:**
177
178
```kotlin
179
import kotlinx.coroutines.*
180
181
// In main function or tests
182
fun main() = runBlocking {
183
launch {
184
delay(1000)
185
println("World!")
186
}
187
println("Hello,")
188
delay(2000)
189
}
190
191
// In tests
192
@Test
193
fun testCoroutine() = runBlocking {
194
val result = async { computeAsync() }
195
assertEquals(42, result.await())
196
}
197
198
// Bridge to suspend functions
199
fun synchronousFunction(): String {
200
return runBlocking {
201
suspendingFunction()
202
}
203
}
204
```
205
206
### Producer (Channel Builder)
207
208
Creates a receive channel from a coroutine that produces values.
209
210
```kotlin { .api }
211
/**
212
* Creates a coroutine that produces values and sends them to a channel
213
* @param context additional context elements
214
* @param capacity channel capacity
215
* @param block the producer coroutine code
216
* @return ReceiveChannel to consume produced values
217
*/
218
fun <E> CoroutineScope.produce(
219
context: CoroutineContext = EmptyCoroutineContext,
220
capacity: Int = 0,
221
block: suspend ProducerScope<E>.() -> Unit
222
): ReceiveChannel<E>
223
224
/**
225
* Scope for the producer coroutine
226
*/
227
interface ProducerScope<in E> : CoroutineScope, SendChannel<E>
228
```
229
230
**Usage Examples:**
231
232
```kotlin
233
import kotlinx.coroutines.*
234
import kotlinx.coroutines.channels.*
235
236
suspend fun numberProducer() {
237
val numbers = produce {
238
for (i in 1..10) {
239
send(i * i) // Send squares
240
delay(100) // Simulate work
241
}
242
}
243
244
// Consume the numbers
245
for (number in numbers) {
246
println("Received: $number")
247
}
248
}
249
250
// Producer with custom capacity
251
suspend fun bufferedProducer() {
252
val channel = produce(capacity = 5) {
253
repeat(20) { i ->
254
send("Item $i")
255
println("Sent item $i")
256
}
257
}
258
259
// Consumer can lag behind due to buffering
260
for (item in channel) {
261
delay(200) // Slow consumer
262
println("Received: $item")
263
}
264
}
265
```
266
267
### CoroutineStart Options
268
269
Configuration for how coroutines are started.
270
271
```kotlin { .api }
272
/**
273
* Defines options for starting coroutines
274
*/
275
enum class CoroutineStart {
276
/** Start coroutine immediately in the current thread until first suspension */
277
DEFAULT,
278
/** Start coroutine lazily when start() or join() is called */
279
LAZY,
280
/** Start coroutine atomically - cannot be cancelled until it starts */
281
ATOMIC,
282
/** Start coroutine immediately in the current thread */
283
UNDISPATCHED
284
}
285
```
286
287
**Usage Examples:**
288
289
```kotlin
290
import kotlinx.coroutines.*
291
292
suspend fun startOptions() = coroutineScope {
293
// Default: scheduled immediately, suspends at first suspension point
294
val defaultJob = launch(start = CoroutineStart.DEFAULT) {
295
delay(100)
296
println("Default started")
297
}
298
299
// Lazy: doesn't start until explicitly started
300
val lazyJob = launch(start = CoroutineStart.LAZY) {
301
println("Lazy started")
302
}
303
304
// Atomic: cannot be cancelled before it starts running
305
val atomicJob = launch(start = CoroutineStart.ATOMIC) {
306
println("Atomic started")
307
}
308
309
// Undispatched: runs immediately in current thread until first suspension
310
val undispatchedJob = launch(start = CoroutineStart.UNDISPATCHED) {
311
println("Undispatched runs immediately")
312
delay(1) // Now it gets dispatched
313
println("After suspension")
314
}
315
316
// Start the lazy job
317
lazyJob.start()
318
319
// Wait for all
320
joinAll(defaultJob, lazyJob, atomicJob, undispatchedJob)
321
}
322
```
323
324
## Builder Comparison
325
326
| Builder | Returns | Use Case | Blocking |
327
|---------|---------|----------|----------|
328
| `launch` | `Job` | Fire-and-forget operations | No |
329
| `async` | `Deferred<T>` | Concurrent computations with results | No |
330
| `withContext` | `T` | Context switching with result | Suspending |
331
| `runBlocking` | `T` | Bridge to blocking code | Yes |
332
| `produce` | `ReceiveChannel<E>` | Value production over time | No |
333
334
## Exception Handling in Builders
335
336
Different builders handle exceptions differently:
337
338
- **launch**: Exceptions are handled by the parent's exception handler or crash the application
339
- **async**: Exceptions are stored in the Deferred and re-thrown when `await()` is called
340
- **withContext**: Exceptions propagate directly to the caller
341
- **runBlocking**: Exceptions propagate to the calling thread
342
- **produce**: Exceptions close the channel and propagate to consumers
343
344
This makes `async` safe for operations that might fail, as exceptions don't crash the parent scope until explicitly checked with `await()`.