https://kotlinlang.org logo
#coroutines
Title
# coroutines
g

Glen

08/03/2021, 8:39 PM
Hello everyone. I am trying to modify a library in order for it to use coroutines, but I want the user-facing function to be called without having to be aware about coroutines. Code can be found here: https://github.com/AnonymousGeekDev/JP2ForAndroid/blob/kotlin-develop/library/src/main/java/com/gemalto/jp2/JP2Decoder.kt#L227 Any help/insight appreciated.
The other question I have is: If I have to call decode in an app that uses this library, do I need to specify the main dispatcher in the app, or could I just call decode() nor mally?
c

Casey Brooks

08/03/2021, 8:45 PM
As you would with any normal async code, you generally have 2 options: block the current thread until the async process completes, or don’t block the thread and pass the data back through a callback function
Copy code
fun decode(): Bitmap? {
    return runBlocking {
        val value = decodeInternal() // a suspending function
        value // return the value
    }
}

fun decode(onCompleted: (Bitmap?)->Unit) {
    GlobalScope.launch {
        val value = decodeInternal() // a suspending function
        onCompleted(value) // send the value through a callback
    }
}
The Main Dispatcher is a statically-defined global variable. You can’t change it, and you don’t need to specify it anywhere either. If your code can access
Dispatchers.Main
, it will already be set to the appropriate value for the platform
But that does beg the question: if the library is an Android library and uses coroutines internally, why not expose that? Android apps nowadays are created with the expectation that you’re using coroutines, and the dependency is already there, so you’re really only limiting yourself or making it less useful to not expose it directly as a coroutine-based API
g

Glen

08/03/2021, 9:16 PM
@Casey Brooks I already have a defined coroutine scope in that class, and I make the launch calls on that scope.
As for exposing the coroutine-based API, for the moment, I want to be able to call the function from an app without having to define a coroutine scope, etc. Just a function call.
I also wonder whether what I am trying to do will not affect the app negatively somehow.
c

Casey Brooks

08/03/2021, 10:11 PM
It’s likely to leak system resources or cause crashes if it’s not tied into the app lifecycle. It’s generally a bad idea (especially on Android) to launch jobs globally, where they can’t be cancelled. That’s why
GlobalScope
now needs a special annotation to use, because it’s generally that should be avoided. So not requiring any special coroutines API really isn’t a feature as much as it is a bug. But all the major Android components now natively work with coroutines in the
-ktx
libraries, so it’s not difficult at all to get ahold of an appropriate coroutine scope (
lifecycleScope
in Activities/Fragments, WorkManager
CoroutineWorker
, etc). And again, if you’re pulling in the dependency on coroutines, you should be following the principles of Structured Concurrency properly. Android development nowadays expects that you’re using coroutines already, and it also expects that anything else using coroutines is following those Structured Concurrency principles, so that everything works nicely with each other. But in the current setup, there’s no real benefit over a normal Thread/Executor, it’s just pulling in a large library but ignoring its benefits
n

Nick Allen

08/03/2021, 11:29 PM
Note that
launch
does not suspend. It starts a coroutine and does not wait for it to finish.
Copy code
var x = 0
someScope.launch {
    someBlockingCode();
    x = 20
 }
println(x) // x is probably still 0.
g

Glen

08/04/2021, 8:00 PM
Thanks for the responses.
11 Views