Callback to Coroutines in Kotlin

Callback to Coroutines in Kotlin

I am Amit Shekhar, a mentor helping developers in getting high-paying tech jobs.

In this blog, we will learn how to convert any Callback to Coroutines in Kotlin.

This article was originally published at amitshekhar.me.

We use many libraries in our Android Project that provides the callback way to use instead of the Coroutines way. As nowadays, we all have started using Kotlin Coroutines in our projects, so it becomes our responsibility to implement things in a way that supports Coroutines.

So, we need to learn how to convert any Callback to Coroutines in Kotlin. And, this is the topic of this blog.

Here, I will take an example of a dummy library just for the sake of understanding.

Assume that we can use a library as below:

Library.doSomething(object : Listener {

    override fun onSuccess(result: Result) {

    }

    override fun onError(throwable: Throwable) {

    }

})

Here, the library does a task and we have a listener through which we get the onSuccess and onError callback.

Now, we want to use this library in the Coroutines way.

Let's do this by creating a suspend function as below:

suspend fun doSomething(): Result {
    return suspendCoroutine { continuation ->
        Library.doSomething(object : Listener {

            override fun onSuccess(result: Result) {
                continuation.resume(result)
            }

            override fun onError(throwable: Throwable) {
                continuation.resumeWithException(throwable)
            }

        })
    }
}

Now, it's time to understand what we have done to convert the Callback to Coroutines.

We have followed the following steps to convert the Callback to Coroutines in Kotlin:

  • Create a suspend function to return the Result.
  • Use suspendCoroutine as the return block.
  • Use continuation.resume(result) for the success.
  • Use continuation.resumeWithException(throwable) for the error.

Now, we can use the above function as below:

launch {
    val result = doSomething()
}

This is how we can convert any callback to Coroutines and use them.

Now, we will discuss one more thing: suspendCancellableCoroutine which is different from suspendCoroutine.

Suppose the library also supports the cancellation of the task.

val id = Library.doSomething(object : Listener {

    override fun onSuccess(result: Result) {

    }

    override fun onError(throwable: Throwable) {

    }

})

and, we can use the cancel() method to cancel the task using the id.

Library.cancel(id)

In this case, we will use the suspendCancellableCoroutine instead of the suspendCoroutine.

Now, again, let's convert this Callback to the Coroutines way by creating a suspend function as below:

suspend fun doSomething(): Result {
    return suspendCancellableCoroutine { continuation ->
        val id = Library.doSomething(object : Listener {

            override fun onSuccess(result: Result) {
                continuation.resume(result)
            }

            override fun onError(throwable: Throwable) {
                continuation.resumeWithException(throwable)
            }

        })

        continuation.invokeOnCancellation {
            Library.cancel(id)
        }
    }
}

We have followed almost the same steps as we have done for the earlier example except for the following two things:

  • Use the suspendCancellableCoroutine instead of suspendCoroutine.
  • Use continuation.invokeOnCancellation as our library supports the cancellation of the task.
continuation.invokeOnCancellation {
    Library.cancel(id)
}

Now, we can use the above function as below:

launch {
    val result = doSomething()
}

This is how we can convert any callback to Coroutines and use them.

Here as we have a way to cancel the task, so we have used the suspendCancellableCoroutine, else we can simply use the suspendCoroutine.

suspendCancellableCoroutine let us use the invokeOnCancellation that is not supported with the suspendCoroutine.

From the official doc: suspendCancellableCoroutine suspends the coroutine like suspendCoroutine but provides a CancellableContinuation to the block.

Now, we can decide which one to use when based on our use case.

So, today we learned how to convert any callback to Coroutines and use them.

Master Kotlin Coroutines from here: Mastering Kotlin Coroutines

That's it for now.

Thanks

Amit Shekhar

You can connect with me on:

Read all of my high-quality blogs here.