DEV Community

Cover image for Utility and Execution Methods in Kotlin: Working with Coroutines
Alan Gomes for Comunidade Dev Space

Posted on

Utility and Execution Methods in Kotlin: Working with Coroutines

1 – Introduction

When working with coroutines in Kotlin , there are utility methods and execution methods that help you manage asynchronous tasks efficiently. These methods are essential tools for controlling:

  • The execution time of the tasks.
  • The context in which tasks are performed.
  • Starting and synchronizing multiple coroutines .

In this article, we will explore the most important methods, such as withTimeout, withContext, launch, async, and others, with practical examples to understand how and when to use them.


2 – Utility Methods

2.1 – withTimeout

  • What is it? Cancels the execution of a block of code if the timeout is reached.
  • When to use? To prevent asynchronous tasks from getting stuck indefinitely.
  • Example:
import kotlinx.coroutines.*

fun main( ) = runBlocking{
try {
        withTimeout ( 1000) { // 1 second timeout
            delay( 2000) // Simulates a long task
            println ( "Task completed!")
}
} catch (e: TimeoutCancellationException ) {
        println ( "Timeout reached! Task canceled.")
}
}
Enter fullscreen mode Exit fullscreen mode

2.2 - withTimeoutOrNull

  • What is it? Similar to withTimeout , but instead of throwing an exception, it returns null if the timeout is reached.
  • When to use? To avoid using exceptions and handle timeout in a more controlled way.
  • Example:
import kotlinx.coroutines.*

fun main() = runBlocking {
    val result = withTimeoutOrNull(1000) { // 1 second timeout
        delay(2000) // Simulates a long task
        "Job completed!"
    }

    if (result == null) {
        println("Timeout reached! Returned null .")
    } else {
        println(result)
    }
}
Enter fullscreen mode Exit fullscreen mode

2.3 – withContext

  • What is it? Changes the context of the coroutine (e.g.: changes the dispatcher ).
  • When to use? temporarily change the dispatcher within a coroutine .
  • Example:
import kotlinx.coroutines .*

fun main() = runBlocking {
    println(" Running on Default Dispatcher : ${Thread.currentThread().name}")

    withContext(Dispatchers.IO) {
        println(" Running in IO Dispatcher: ${Thread.currentThread().name}")
    }

    println("Back to Default Dispatcher : ${Thread.currentThread().name}")
}
Enter fullscreen mode Exit fullscreen mode

2.4 – delay

  • What is it? Suspends the execution of a coroutine for a period of time, without blocking the thread.
  • When to use? To simulate time-consuming tasks or wait for a response.
  • Example:
import kotlinx.coroutines.*

fun main() = runBlocking {
    println("Starting task...")
    delay(1000) // Suspend for 1 second
    println("Task completed!")
}
Enter fullscreen mode Exit fullscreen mode

2.5 – yield

  • What is it? Yields the current context, allowing other coroutines to run.
  • When to use? To improve cooperation between coroutines and avoid unnecessary blocking.
  • Example:
import kotlinx.coroutines.*

fun main() = runBlocking{
    launch {
        repeat(3) { i ->
            println(" Coroutine 1 - Iteration $i")
            yield() // Yield the context
        }
    }

    launch {
        repeat(3) { i ->
            println(" Coroutine 2 - Iteration $i")
            yield() // Yield the context
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

3 – Execution Methods

3.1 – launch

  • What is it? Creates a new coroutine and starts its execution immediately.
  • When to use? When you don't need to return a result from the coroutine .
  • Example:
import kotlinx.coroutines.*

fun main() = runBlocking {
    launch {
        println("Coroutine started!")
        delay(1000)
        println("Coroutine finished!")
    }
}
Enter fullscreen mode Exit fullscreen mode

3.2 – async

  • What is it? Creates a new coroutine that returns a value (deferred).
  • When to use? For asynchronous tasks that return results.
  • Example:
import kotlinx.coroutines.*

fun main() = runBlocking {
    val result = async {
        delay(1000)
        "Result calculated!"
    }

    println("Waiting for result...")
    println("Result:${result.await()}")
}
Enter fullscreen mode Exit fullscreen mode

3.3 – runBlocking

  • What is it? Executes coroutines in a blocking function.
  • When to use? Only in specific cases, such as small scripts or for quick testing.
  • Example:
import kotlinx.coroutines.*

fun main( ) = runBlocking {
    println("Starting runBlocking")
    delay(1000)
    println("Finalizing runBlocking")
}
Enter fullscreen mode Exit fullscreen mode

4 – Comparison: Utility Methods vs. Execution Methods

Aspect Utility Methods Execution Methods
Main Function Control time, context, and suspension. Start and manage coroutines.
Return Value Generally, they do not return values. Some return values (e.g. async).
Main Examples withTimeout, delay, yield launch, async, runBlocking

5 – Conclusion

Utility and runner methods are indispensable tools in the Kotlin coroutine ecosystem. They allow you to control asynchronous execution in a precise, scalable, and efficient way.

Summary of Methods:

1. Utilities:

  • Timeout control: withTimeout, withTimeoutOrNull.
  • Context: withContext.
  • Suspension: delay, yield.

2. Execution:

  • launch for coroutines that do not return values.
  • async for coroutines that return results.
  • runBlocking to run coroutines in scripts or simple tests.

In the next article, we will explore how to efficiently test coroutines and flows with native tools and libraries like Turbine.

Reference
Official Kotlin documentation on coroutines

Top comments (0)