How Suspend Functions Work in Kotlin: Under the Hood in Android

Sandeep Kella
4 min readJust now

Hey there! Let’s dive into the fascinating world of suspend functions in Kotlin. If you’re into Android development, you’ve probably heard about them and maybe even used them. But have you ever wondered what’s really going on under the hood? Let’s break it down in a fun and easy way, with some everyday analogies to keep things interesting.

What Are Suspend Functions?

Imagine you’re a chef in a busy kitchen. You’ve got a lot of tasks to juggle — prepping ingredients, cooking dishes, and plating food. Now, think of each task as a function in your Android app. Some tasks can be done quickly (like slicing a tomato), but others take time (like simmering a stew). You don’t want to be stuck waiting for the stew to cook before you can slice the tomato, right? That’s where suspend functions come in!

In Kotlin, a suspend function is like a smart chef’s assistant who takes care of the long-running tasks, freeing you up to do other things. When you call a suspend function, you’re saying, “Hey, this might take a while. Let’s not block the main thread while we wait.”

Example of a Suspend Function

Here’s a simple example:

suspend fun fetchData(): String {
// Simulating a long-running task
delay(1000)
return "Data fetched"
}
fun main() {
// Using a coroutine to call the suspend function
GlobalScope.launch {
val result = fetchData()
println(result) // Output: Data fetched
}
}

In this example, fetchData is a suspend function that simulates a long-running task with a delay of 1 second. We use a coroutine to call this function without blocking the main thread.

How Suspend Functions Work Under the Hood

Now, let’s peek into the kitchen and see what our assistant is really doing. When you mark a function with the suspend keyword, Kotlin does some behind-the-scenes magic to handle it.

Step 1: Suspend Marker

The suspend keyword is like a special badge that tells Kotlin, “This function might take a while.” When the function hits a delay or a long-running operation, it can pause (or “suspend”) its work and let other tasks run in the meantime.

Step 2: Continuation

Behind the scenes, Kotlin creates a continuation object. Think of this as a bookmark in a recipe book. When the function suspends, the continuation saves its current state (like the ingredients and cooking steps). When it’s ready to resume, it picks up right where it left off.

Step 3: State Machine

Kotlin turns your suspend function into a state machine. Imagine the function as a series of checkpoints. At each checkpoint, it can decide to pause and let someone else (another function or coroutine) use the kitchen. When it resumes, it continues from the last checkpoint.

Step 4: Non-Blocking

Suspend functions are non-blocking. This means they don’t hold up the main thread. It’s like having an extra pair of hands in the kitchen that can keep working while you take care of other tasks.

Under the Hood Example

Let’s dig into what really happens. Consider this simple suspend function:

suspend fun fetchData(): String {
delay(1000)
return "Data fetched"
}

Kotlin transforms it into something like this (in pseudo-code):

Object fetchData(Continuation<? super String> continuation) {
switch (continuation.getLabel()) {
case 0:
continuation.setLabel(1);
if (delay(1000, continuation) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED;
case 1:
return "Data fetched";
}
}

Here’s what’s happening:

  1. Continuation Object: Keeps track of the state.
  2. State Machine: Uses labels to manage the function’s progress.
  3. Non-Blocking Call: When delay is called, it checks if it should suspend. If yes, it returns COROUTINE_SUSPENDED and pauses.

Real-World Analogy

Think of a suspend function as a chef making a multi-course meal. The chef can start a dish, put it in the oven, and then work on another dish while the first one cooks. When the oven timer goes off, the chef resumes working on the first dish.

Practical Use in Android

In Android, suspend functions are often used for tasks like network requests or database operations — things that take time and shouldn’t block the main thread.

Example with Network Request

suspend fun fetchUserData(): User {
// Simulating network call
delay(2000)
return User("John Doe")
}
fun main() {
GlobalScope.launch {
val user = fetchUserData()
println(user.name) // Output: John Doe
}
}

In this example, fetchUserData simulates a network call that takes 2 seconds. Using coroutines, we can call this function without freezing the app’s UI.

Conclusion

Suspend functions in Kotlin are a powerful tool for handling long-running tasks in a non-blocking way. They let you write cleaner and more efficient code by managing tasks behind the scenes, much like a smart assistant in a busy kitchen.

--

--

Sandeep Kella

Android developer @PhonePe, writes about Android development and productivity.