Whenever we need to write asynchronous code we tend to use callbacks which allow us to trigger an action and, instead of waiting for it to finish, get notified through the callback for the action’s completion. Coroutines change that and help us write asynchronous code but in a sequential way.
This means that instead of writing code like this:
we can write it like this:
But what do we do when there is no easy way to remove callbacks from existing code or when we use a third party library that is not coroutines ready? This is where
suspendCoroutine comes to save the day.
suspendCoroutine is a function that does exactly what is says. It suspends the coroutine that it was called from and provides a way to resume it.
Lets have an example. The code here:
simply prints 1 2 3 4 Done!. If we change it to:
it will print 1 2 3 and then it will just wait. We suspended the coroutine but we did not resume it. To do so we will use the continuation instance that
now it prints 1 2 3 … 4 Done!. The coroutine printed the first three numbers, got suspended, while being suspended another block of code got executed and printed the dots and then resumed the coroutine allowing it to print the final number and done.
Back to our first example. Lets say that
downloadTasks cannot be changed. We still need to call it and provide a callback for its results.
What we need to do is to suspend the coroutine, call
downloadTasks to.. well.. download the tasks and provide a callback that upon completion it will resume the coroutine with the tasks at hand.
To achieve that we first need to create an adapter that will connect the callback with a continuation:
and then call
That’s it. The adapter resumes the coroutine by providing the tasks that are then returned to the suspension point.
One more thing
suspendCoroutine there is also
suspendCancellableCoroutine which provides a cancellable continuation. That means that in addition of resuming we can also execute code upon cancellation:
this will print Downloading… and then Cancelled…