Coroutines 4
Coroutines 4
26
Resume
println("After")
}
// Before
// After
How does suspension work? 27
This is a simple program that will print “Before” and “After”. What
will happen if we suspend in between these two prints? For that,
we can use the suspendCoroutine function provided by the standard
Kotlin library⁹.
suspendCoroutine<Unit> { }
println("After")
}
// Before
If you call the above code, you will not see the “After”, and the code
will not stop running (as our main function never finished). The
coroutine is suspended after “Before”. Our game was stopped and
never resumed. So, how can we resume? Where is this aforemen-
tioned Continuation?
Take a look again at the suspendCoroutine invocation and notice that
it ends with a lambda expression ({ }). The function passed as an
argument will be invoked before the suspension. This function gets
a continuation as an argument.
println("After")
}
// Before
// Before too
println("After")
}
// Before
// After
We could also start a different thread that will sleep for a set duration
and resume after that time:
println("After")
}
// Before
// Suspended
// (1 second delay)
// After
// Resumed
println("After")
}
// Before
// (1 sec)
// After
//sampleEnd
}, 1000, TimeUnit.MILLISECONDS)
}
println("After")
}
// Before
// (1 second delay)
// After
Suspending for a set amount of time seems like a useful feature. Let’s
extract it into a function. We will name it delay.
delay(1000)
println("After")
}
// Before
// (1 second delay)
// After
The executor still uses a thread, but it is one thread for all coroutines
using the delay function. This is much better than blocking one
thread every time we need to wait for some time.
How does suspension work? 32
This is exactly how delay from the Kotlin Coroutines library used to
be implemented. The current implementation is more complicated,
mainly so as to support testing, but the essential idea remains the
same.
One thing that might concern you is why we passed Unit to the
resume function. You might also be wondering why we used Unit as a
type argument for the suspendCoroutine. The fact that these two are
the same is no coincidence. Unit is also returned from the function
and is the generic type of the Continuation parameter.
This does not fit well with the game analogy. I don’t know of any
game in which you can put something inside the game when re-
suming a save¹¹ (unless you cheated and googled how to solve the
next challenge). However, it makes perfect sense with coroutines.
Often we are suspended because we are waiting for some data, such
as a network response from an API. This is a common scenario.
Your thread is running business logic until it reaches a point where
it needs some data. So, it asks your network library to deliver it.
Without coroutines, this thread would then need to sit and wait.
This would be a huge waste as threads are expensive, especially if
this is an important thread, like the Main Thread on Android. With
coroutines, it just suspends and gives the library a continuation with
the instruction “Once you’ve got this data, just send it to the resume
function”. Then the thread can go do other things. Once the data is
there, the thread will be used to resume from the point where the
coroutine was suspended.
To see this in action, let’s see how we might suspend until we re-
ceive some data. In the example below, we use a callback function
requestUser that is implemented externally.
You might wonder what happens if the API gives us not data but
some kind of problem. What if the service is dead or responds
with an error? In such a case, we cannot return data; instead, we
should throw an exception from the place where the coroutine was
suspended. This is where we need to resume with an exception.
How does suspension work? 35