Mobile Development 20 min read

Understanding Kotlin Coroutines

This article provides a comprehensive guide to Kotlin coroutines, covering their concepts, creation methods (launch, runBlocking, async), nesting, suspend functions, cancellation, timeout handling, dispatchers, scopes, underlying implementation, and a practical Retrofit‑OkHttp example for asynchronous network requests in Android.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Understanding Kotlin Coroutines

Coroutines are a long‑standing concept now supported by many languages such as Lua, C#, Go, and Kotlin. In Android, Kotlin coroutines are lightweight threads that schedule tasks on existing JVM threads, allowing sequential code to appear concurrent through suspension.

The kotlinx.coroutines library from JetBrains offers primitives like launch and async. Coroutines run on a thread and can be thought of as multiple coroutines within a single thread, where each coroutine may suspend and resume, giving the illusion of parallelism.

1. Coroutine creation

launch returns a Job and creates a non‑blocking coroutine. Example:

val coroutineJob = GlobalScope.launch {
    Log.d(TAG, "current Thread is ${Thread.currentThread()}")
}
Log.d(TAG, "GlobalScope.launch create coroutine")

When launched on Dispatchers.Main, the coroutine runs on the main thread without blocking it.

runBlocking creates a blocking coroutine that suspends the calling thread until completion. Example:

val coroutine2 = runBlocking {
    Log.d(TAG, "current Thread is ${Thread.currentThread()}")
}
Log.d(TAG, "runBlocking create coroutine")

Running with Dispatchers.IO demonstrates that the thread is blocked for the duration of the coroutine.

async returns a Deferred and is also non‑blocking. Example measuring concurrent execution:

runBlocking {
    val time = measureTimeMillis {
        val d1 = async { delay(2000L); Log.d(TAG, "deferred1 result") }
        val d2 = async { delay(3000L); Log.d(TAG, "deferred2 result") }
        Log.d(TAG, "result is ${d1.await() + d2.await()}")
    }
    Log.d(TAG, "cost time is $time")
}

2. Nested coroutines can be created without an explicit

GlobalScope</>, inheriting the parent’s scope and dispatcher:</p>
<pre><code>runBlocking {
    launch { Log.d(TAG, "launch current Thread is ${Thread.currentThread()}") }
    Log.d(TAG, "current Thread is ${Thread.currentThread()}")
}

Parent cancellation propagates to children, and the parent waits for all children to finish. 3. Suspend functions are declared with the suspend modifier and can only be called from a coroutine or another suspend function. Example:

suspend fun doWork() {
    Log.d(TAG, "doWork start")
    delay(5000)
    Log.d(TAG, "doWork end")
}

4. Cancellation and timeout are handled via Job.cancel() , cancelAndJoin() , withTimeout , and withTimeoutOrNull . Example:

runBlocking {
    val job = launch { delay(500); Log.d(TAG, "launch running") }
    Log.d(TAG, "waiting launch")
    job.cancelAndJoin()
    Log.d(TAG, "runBlocking end")
}

Timeout throws TimeoutCancellationException unless withTimeoutOrNull is used. 5. Dispatchers and scopes control the thread on which a coroutine runs. Common dispatchers include Dispatchers.Unconfined , Dispatchers.Default , Dispatchers.IO , and custom single‑thread contexts. Example:

runBlocking {
    launch { Log.d(TAG, "Im working in thread ${Thread.currentThread().name}") }
    launch(Dispatchers.Unconfined) { Log.d(TAG, "Unconfined before"); delay(500); Log.d(TAG, "Unconfined after") }
    launch(Dispatchers.Default) { Log.d(TAG, "Default thread ${Thread.currentThread().name}") }
    launch(newSingleThreadContext("MyOwnThread")) { Log.d(TAG, "MyOwnThread ${Thread.currentThread().name}") }
    launch(Dispatchers.IO) { Log.d(TAG, "IO thread ${Thread.currentThread().name}") }
}

Switching contexts inside a coroutine is done with withContext :

runBlocking {
    launch {
        Log.d(TAG, "start in thread ${Thread.currentThread().name}")
        withContext(Dispatchers.IO) { delay(5000); Log.d(TAG, "working in thread ${Thread.currentThread().name}") }
        Log.d(TAG, "end in thread ${Thread.currentThread().name}")
    }
}

6. Underlying implementation relies on suspend functions being compiled into state‑machine Java code with an implicit Continuation parameter. The compiler generates a label‑based state machine that resumes execution at the appropriate point. 7. Practical application demonstrates replacing RxJava with coroutines for a Retrofit network request. A ViewModel uses mainScope.launch and withContext(Dispatchers.IO) to fetch data asynchronously:

class MainViewModel : ViewModel() {
    private val mainScope = MainScope()
    fun getDataFromServer() = mainScope.launch {
        val json = withContext(Dispatchers.IO) { repository.getDataFromServer() }
        data.postValue(json)
    }
    override fun onCleared() { super.onCleared(); mainScope.cancel() }
}

The Retrofit service declares a suspend function, eliminating callbacks entirely. Conclusion Kotlin coroutines simplify asynchronous programming in Android by allowing developers to write sequential‑style code for network I/O, file operations, and more, while providing powerful constructs such as Flow and Channel that can replace RxJava in many scenarios.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

KotlinCoroutinesRetrofitSuspend Functions
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.