Kotlin's coroutines are an excellent feature of the language that makes asynchronous programming enjoyable and easy to understand.
However, even if you have organized your project neatly and extensively use coroutines, you may encounter a third-party library at some point that still uses old-fashioned callbacks. Combining callbacks and coroutines can be unpleasant, to say the least.
Luckily, there is a solution to this problem. You can wrap these callbacks and "transform" them into coroutines. It's generally a good practice to wrap your external dependencies and provide a consistent coroutine-style interface, regardless of the interface offered by the third-party libraries.
Below is a short code example that demonstrates how to quickly convert a library that uses callbacks into a coroutine interface, so you can start using it promptly.
suspend fun callCallbackBasedSdkSomeMethod(): String {
return suspendCancellableCoroutine { continuation -> // 1.
CallbackBasedSdk.getInstance().someMethod( // 2.
object : Callback {
override fun onSuccess(result: String) {
continuation.resume(result) // 3.
}
override fun onFailure(e: TerminalException) {
continuation.resumeWithException(e) // 4.
}
},
)
continuation.invokeOnCancellation { // 5.
CallbackBasedSdk.getInstance().stopSomeMethod()
}
}
}
- Use Kotlin's
suspendCancellableCoroutine
to convert calls from a callback-based SDK to a coroutine-based one. - Inside the
suspendCancellableCoroutine
'sblock
parameter call the callback-based SDK method as you would normally do. - Use the
continuation.resumt()
to resume the execution of the coroutine and provide results. - Optionally, use
continuation.resumeWithException()
to throw an exception in the context of the coroutine. - In case the coroutine is canceled, you can define if any action needs to be taken to cancel the request in flight.
Hopefully, this help you maintain a consistent coroutine-based codebase in your Kotlin project.
Happy coding!
Top comments (1)
Thanks for sharing! This is very handy indeed, I recently did the same to consume the Firebase Storage API as It fully relies on a Callback approach.