I am trying to write a class to easily chain code run in different coroutine contexts.
Ideally, I would like to use it like this:
io {
// Run IO code that returns an object (nullable)
} ui { ioResult->
// Run UI code using the returned object (non-nullable)
} ifNull {
// Run UI code when the returned object is null
}
What I have so far works like this:
GlobalScope.launch {
CoroutineLinker(null).io {
// Run IO code
} ui { ioResult ->
ioResult?.also {
// Run UI code after null check
} ?: run {
// Run UI code when null
}
} ifNull {
// Redundant block
}
}
As you can see there is still quite some work left but I am stuck, so I share this with you:
class CoroutineLinker<T> (
private val value: T?
) {
suspend infix fun <K> io (block: suspend () -> K?): CoroutineLinker<K?> {
return withContext(Dispatchers.IO) {
CoroutineLinker(block())
}
}
suspend infix fun ui (block: suspend (value: T) -> Unit): CoroutineLinker<T> {
return withContext(Dispatchers.Main) {
if (value != null ) {
block(value)
}
this@CoroutineLinker
}
}
suspend infix fun ifNull (block: suspend () -> Unit) {
return withContext(Dispatchers.Main) {
if (value == null) {
block()
}
}
}
}
Any input is welcome! :)
I think this will do what you need:
suspend fun <K : Any> io (block: suspend () -> K?) = CoroutineLinker(null).io(block)
class CoroutineLinker<T : Any> (
private val value: T?
) {
suspend infix fun <K : Any> io (block: suspend () -> K?): CoroutineLinker<K> {
return withContext(Dispatchers.IO) {
CoroutineLinker(block())
}
}
suspend infix fun ui (block: suspend (value: T) -> Unit): CoroutineLinker<T> {
if (value != null ) {
withContext(Dispatchers.Main) {
block(value)
}
}
return this
}
suspend infix fun ifNull (block: suspend () -> Unit) {
if (value == null) {
withContext(Dispatchers.Main) {
block()
}
}
}
}
I changed 3 things:
CoroutineLinker
to Any
.io
function.if
and withContext
in both functions - this is just optimization, it wasn't required.