public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
...
}
public interface CoroutineScope {
public val coroutineContext: CoroutineContext
}
public interface Continuation<in T> {
public val context: CoroutineContext
public fun resumeWith(result: Result<T>)
}
launch(CoroutineName("Name1")) { ... }
launch(CoroutineName("Name2") + Job()) { ... }
//1
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
//sampleStart
fun main() {
val name: CoroutineName = CoroutineName("A name")
val element: CoroutineContext.Element = name
val context: CoroutineContext = element
val job: Job = Job()
val jobElement: CoroutineContext.Element = job
val jobContext: CoroutineContext = jobElement
}
//sampleEnd
//2
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
//sampleStart
fun main() {
val ctx: CoroutineContext = CoroutineName("A name")
val coroutineName: CoroutineName? = ctx[CoroutineName]
// or ctx.get(CoroutineName)
println(coroutineName?.name) // A name
val job: Job? = ctx[Job] // or ctx.get(Job)
println(job) // null
}
//sampleEnd
data class CoroutineName(
val name: String
) : AbstractCoroutineContextElement(CoroutineName) {
override fun toString(): String = "CoroutineName($name)"
companion object Key : CoroutineContext.Key<CoroutineName>
}
interface Job : CoroutineContext.Element {
companion object Key : CoroutineContext.Key<Job>
// ...
}
//3
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
//sampleStart
fun main() {
val ctx1: CoroutineContext = CoroutineName("Name1")
println(ctx1[CoroutineName]?.name) // Name1
println(ctx1[Job]?.isActive) // null
val ctx2: CoroutineContext = Job()
println(ctx2[CoroutineName]?.name) // null
println(ctx2[Job]?.isActive) // true, because "Active"
// is the default state of a job created this way
val ctx3 = ctx1 + ctx2
println(ctx3[CoroutineName]?.name) // Name1
println(ctx3[Job]?.isActive) // true
}
//sampleEnd
//4
import kotlinx.coroutines.CoroutineName
import kotlin.coroutines.CoroutineContext
//sampleStart
fun main() {
val ctx1: CoroutineContext = CoroutineName("Name1")
println(ctx1[CoroutineName]?.name) // Name1
val ctx2: CoroutineContext = CoroutineName("Name2")
println(ctx2[CoroutineName]?.name) // Name2
val ctx3 = ctx1 + ctx2
println(ctx3[CoroutineName]?.name) // Name2
}
//sampleEnd
//5
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
//sampleStart
fun main() {
val empty: CoroutineContext = EmptyCoroutineContext
println(empty[CoroutineName]) // null
println(empty[Job]) // null
val ctxName = empty + CoroutineName("Name1") + empty
println(ctxName[CoroutineName]) // CoroutineName(Name1)
}
//sampleEnd
//6
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Job
//sampleStart
fun main() {
val ctx = CoroutineName("Name1") + Job()
println(ctx[CoroutineName]?.name) // Name1
println(ctx[Job]?.isActive) // true
val ctx2 = ctx.minusKey(CoroutineName)
println(ctx2[CoroutineName]?.name) // null
println(ctx2[Job]?.isActive) // true
val ctx3 = (ctx + CoroutineName("Name2"))
.minusKey(CoroutineName)
println(ctx3[CoroutineName]?.name) // null
println(ctx3[Job]?.isActive) // true
}
//sampleEnd
//7
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
//sampleStart
fun main() {
val ctx = CoroutineName("Name1") + Job()
ctx.fold("") { acc, element -> "$acc$element " }
.also(::println)
// CoroutineName(Name1) JobImpl{Active}@dbab622e
val empty = emptyList<CoroutineContext>()
ctx.fold(empty) { acc, element -> acc + element }
.joinToString()
.also(::println)
// CoroutineName(Name1), JobImpl{Active}@dbab622e
}
//sampleEnd
//8
import kotlinx.coroutines.*
//sampleStart
fun CoroutineScope.log(msg: String) {
val name = coroutineContext[CoroutineName]?.name
println("[$name] $msg")
}
fun main() = runBlocking(CoroutineName("main")) {
log("Started") // [main] Started
val v1 = async {
delay(500)
log("Running async") // [main] Running async
42
}
launch {
delay(1000)
log("Running launch") // [main] Running launch
}
log("The answer is ${v1.await()}")
// [main] The answer is 42
}
//sampleEnd
//9
import kotlinx.coroutines.*
fun CoroutineScope.log(msg: String) {
val name = coroutineContext[CoroutineName]?.name
println("[$name] $msg")
}
//sampleStart
fun main() = runBlocking(CoroutineName("main")) {
log("Started") // [main] Started
val v1 = async(CoroutineName("c1")) {
delay(500)
log("Running async") // [c1] Running async
42
}
launch(CoroutineName("c2")) {
delay(1000)
log("Running launch") // [c2] Running launch
}
log("The answer is ${v1.await()}")
// [main] The answer is 42
}
//sampleEnd
defaultContext + parentContext + childContext
//10
import kotlinx.coroutines.*
import kotlin.coroutines.coroutineContext
suspend fun printName() {
println(coroutineContext[CoroutineName]?.name)
}
suspend fun main() = withContext(CoroutineName("Outer")) {
printName() // Outer
launch(CoroutineName("Inner")) {
printName() // Inner
}
delay(10)
printName() // Outer
}
class MyCustomContext : CoroutineContext.Element {
override val key: CoroutineContext.Key<*> = Key
companion object Key :
CoroutineContext.Key<MyCustomContext>
}
//11
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
class CounterContext(
private val name: String
) : CoroutineContext.Element {
override val key: CoroutineContext.Key<*> = Key
private var nextNumber = 0
fun printNext() {
println("$name: $nextNumber")
nextNumber++
}
companion object Key :CoroutineContext.Key<CounterContext>
}
suspend fun printNext() {
coroutineContext[CounterContext]?.printNext()
}
suspend fun main(): Unit =
withContext(CounterContext("Outer")) {
printNext() // Outer: 0
launch {
printNext() // Outer: 1
launch {
printNext() // Outer: 2
}
launch(CounterContext("Inner")) {
printNext() // Inner: 0
printNext() // Inner: 1
launch {
printNext() // Inner: 2
}
}
}
printNext() // Outer: 3
}
//12
import kotlinx.coroutines.withContext
import java.util.*
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
import kotlin.test.assertEquals
data class User(val id: String, val name: String)
abstract class UuidProviderContext :
CoroutineContext.Element {
abstract fun nextUuid(): String
override val key: CoroutineContext.Key<*> = Key
companion object Key :
CoroutineContext.Key<UuidProviderContext>
}
class RealUuidProviderContext : UuidProviderContext() {
override fun nextUuid(): String =
UUID.randomUUID().toString()
}
class FakeUuidProviderContext(
private val fakeUuid: String
) : UuidProviderContext() {
override fun nextUuid(): String = fakeUuid
}
suspend fun nextUuid(): String =
checkNotNull(coroutineContext[UuidProviderContext]) {
"UuidProviderContext not present"
}
.nextUuid()
// function under test
suspend fun makeUser(name: String) = User(
id = nextUuid(),
name = name
)
suspend fun main(): Unit {
// production case
withContext(RealUuidProviderContext()) {
println(makeUser("Michał"))
// e.g. User(id=d260482a-..., name=Michał)
}
// test case
withContext(FakeUuidProviderContext("FAKE_UUID")) {
val user = makeUser("Michał")
println(user) // User(id=FAKE_UUID, name=Michał)
assertEquals(User("FAKE_UUID", "Michał"), user)
}
}