CoroutineWorker
Specs
- Supported on Native and JVM
- Kotlin 1.3.41
About
CoroutineWorker helps support multi-threaded coroutine usage in common code that works in Kotlin/Native and on JVM until kotlinx.coroutines has full support for native, multi-threaded coroutines.
Sample Usage
Spawning Asynchronous Work
Use execute
to start background work from common code:
val worker = CoroutineWorker.execute {
// - In here, `this` is a `CoroutineScope`
// - Run suspend functions, call launch, etc.
// - This code runs in a thread pool
}
// Tells the worker to cancel (uses standard coroutine cancellation)
worker.cancel()
// Tells the worker to cancel; it suspends until cancellation is finished
worker.cancelAndJoin()
Waiting on Asynchronous Work to Complete
From a coroutine context (i.e. somewhere you can call a suspend fun
), use withContext
to kick off work to another thread. It will non-blocking/suspend wait for the cross-thread work to complete:
suspend fun doWork() {
val result = CoroutineWorker.withContext {
// This is similar to execute, but it returns
// the result of the work at the end of this lambda
1
}
print(result) // prints 1
}
This is like using withContext
on JVM to switch coroutine contexts. You can also properly pass a dispatcher, which will be used on JVM: withContext(Dispatchers.IO) { โฆ }
. The idea here is that this will be easy to migrate when we do get multi-threaded coroutine support in Kotlin/Native.
Waiting on Asynchronous Callback-based Work
Use threadSafeSuspendCallback
to bridge callback-style async work into your code as a suspend fun
:
suspend fun performNetworkFetch() {
val result = threadSafeSuspendCallback { completion ->
// example: fetch network data that isn't coroutine-compatible
fetchNetworkData { networkResult ->
// notify that async work is complete
completion(networkRestul)
}
}
// result is now available here
}
CoroutineWorker Prefers Frozen State
Object detachment (i.e. transferring object ownership from one thread to another) is relatively difficult to achieve (outside of simple scenarios) compared to working with objects that are frozen and immutable. Because of this, CoroutineWorker prefers taking the frozen, immutable route:
- Lambdas passed to CoroutineWorker are automatically frozen when they are going to be passed across threads.
- The result value from
withContext
is also frozen.
Tips for Working with Frozen State
- Be careful about what your frozen lambdas capture; those objects will be frozen too. Especially, watch for implicit references to
this
. - Call
ensureNeverFrozen()
on objects that you don't expect to ever be frozen.