Credit: https://kotlinlang.org/assets/images/twitter-card/kotlin_800x320.png

Kotlin coroutines: interacting with external libraries and existing code

Andrea Bresolin
3 min readMar 10, 2018

--

In this post, I’m going to show a simple pattern to turn any code from asynchronous into synchronous with Kotlin coroutines. This is especially useful when dealing with existing code or external libraries that have their own way to handle asynchronous events, for example through callbacks.

At the time of writing, the available version of the coroutines library is 0.22.5 and the available version of Kotlin is 1.2.30. These are the versions that I’ll use as a reference.

Making RxJava synchronous

Let’s start with an example using RxJava that will make you understand the general pattern quickly.

Typical RxJava code in Android looks like this:

fun execute() {
myRepository.myRemoteCall()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onSuccess, this::onError)
}
private fun onSuccess(result: MyResultType) {
...
}
private fun onError(throwable: Throwable) {
...
}

This code uses callbacks to handle the asynchronous events. Let’s make it coroutines-friendly. The changes are highlighted in bold.

suspend fun execute(): MyResultType {
return suspendCoroutine<MyResultType> { continuation ->
myRepository.myRemoteCall()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ result -> onSuccess(continuation, result) },
{ throwable -> onError(continuation, throwable) })
}
}
private fun onSuccess(
continuation: Continuation,
result: MyResultType) {
...
continuation.resume(result)
}
private fun onError(
continuation: Continuation,
throwable: Throwable) {
...
continuation.resumeWithException(throwable)
}

With suspendCoroutine() we can basically make the current coroutine suspend immediately. This method gives us a continuation object for the current coroutine. With the continuation, we can manually control when we want to resume the coroutine.

With continuation.resume() we can return a value from our suspend function in case of success.

With continuation.resumeWithException() we can resume the coroutine with an exception in case of error.

The general pattern: from asynchronous into synchronous

Now that we’ve seen a specific example for a single tool (RxJava in this case), we can take a look at the general pattern to transform any existing asynchronous code with callbacks, coming from external libraries or existing code, into synchronous-looking code with Kotlin coroutines.

suspend fun execute(): MyResultType {
return suspendCoroutine<MyResultType> { continuation ->
...execute the asynchronous code with callbacks...
...call onSuccess(continuation, result) passing the continuation in case of a successful execution... ...call onError(continuation, throwable) passing the continuation in case of an error during the execution...
}
}
private fun onSuccess(
continuation: Continuation,
result: MyResultType) {
...custom processing logic.. continuation.resume(result)
}
private fun onError(
continuation: Continuation,
throwable: Throwable) {
...custom processing logic... continuation.resumeWithException(throwable)
}

And here is the pattern as a list of steps:

  • add the suspend modifier to the asynchronous method and specify the result type
  • wrap all the logic of the asynchronous method into
    return suspendCoroutine<…result type…> {}
  • pass the continuation to the success and error callbacks
  • use continuation.resume() or continuation.resumeWithException() to return the result or return an exception from the suspend function

With this pattern, we can have our suspend function that can be used with Kotlin coroutines.

Conclusion

We’ve seen a possible pattern to deal with existing asynchronous code and make it play nicely with Kotlin coroutines by having our own suspend functions. This is a possible solution and not necessarily the only one.

If you want a more in-depth explanation of other coroutines concepts and how they can be applied to Android, take a look at my other post titled Playing with Kotlin in Android: coroutines and how to get rid of the callback hell.

--

--