Mobile Development 18 min read

Understanding Kotlin Coroutines: Concepts, Usage, and Comparison with RxJava

This article explains Kotlin coroutine fundamentals, creation, launch and async usage, suspension functions, withContext, and compares coroutine-based implementations with RxJava in Android development, providing code examples and best‑practice guidance, including performance considerations and migration advice.

JD Retail Technology
JD Retail Technology
JD Retail Technology
Understanding Kotlin Coroutines: Concepts, Usage, and Comparison with RxJava

Introduction

Coroutines are a concurrency design pattern provided by Kotlin. They allow developers to write asynchronous code in a structured way, making code appear linear.

Basic Concepts

CoroutineScope defines the scope for new coroutines and provides functions to create, start, and cancel coroutines. Built‑in scopes include MainScope, LifecycleScope, ViewModelScope, and GlobalScope.

Coroutine builders such as launch and async are extension functions of CoroutineScope.

CoroutineContext is a linked‑list‑like structure that holds elements like Job and Dispatcher.

CoroutineStart defines start modes: DEFAULT, LAZY, ATOMIC, UNDISPATCHED.

Dispatchers: DEFAULT (CPU‑bound), Main (UI thread), IO (I/O‑bound), Unconfined (no thread restriction).

suspending lambda, suspension point, and suspend functions.

Creating and Starting Coroutines

launch

coroutineScope.launch(Dispatchers.IO) { /* example (1) */ }
coroutineScope.launch(Dispatchers.Main) { /* example (2) */ }

Example (1) creates a coroutine that runs on the IO thread; example (2) runs on the UI thread.

val job: Job = coroutineScope.launch(Dispatchers.IO, CoroutineStart.LAZY) { /* example (1) */ }
job.start()

Using CoroutineStart.LAZY creates the coroutine but does not start it until job.start() is called.

async

When two network requests must be completed before updating UI, async can run them concurrently.

coroutineScope.launch(Dispatchers.Main) {
    val async1 = async(Dispatchers.IO) { "simulate user info" }
    val async2 = async(Dispatchers.IO) { "simulate company info" }
    handleData(async1.await(), async2.await())
}

async returns a Deferred , which is a Job with a result that can be obtained via await() .

Kotlin Coroutine Advantages

Compared with traditional Callback code, coroutine code eliminates nested callbacks, removes explicit thread switching for UI updates, and reduces boilerplate.

// Callback version
apiService.getUserInfo().enqueue(object : Callback
{ ... })

// Coroutine version
coroutineScope.launch(Dispatchers.Main) {
    val userInfo = coroutineApiService.getUserInfo()
    tvName.text = userInfo.userName
}

Using withContext

withContext is a suspending function that switches execution to a specified dispatcher and automatically returns to the original context after the block finishes.

coroutineScope.launch(Dispatchers.Main) {
    val data = withContext(Dispatchers.IO) { handleFileData() }
    tvName.text = data
}

Suspending Functions

The suspend keyword marks a function that can pause a coroutine without blocking the underlying thread.

Practical Case: JD.com App

In a JD.com feature, coroutines are used to assemble static and dynamic data concurrently.

private val scope = MainScope()
private fun assembleDataList(response: PlatformResponse?) = scope.launch(CoroutineExceptionHandler { _, exception -> /* handle */ }) {
    val localStaticData = async(start = CoroutineStart.LAZY) { getLocalStaticData() }
    val dynamicData = async(start = CoroutineStart.LAZY) { getDynamicData(response) }
    getAssembleDataListFunc(localStaticData.await(), dynamicData.await())
}

Comparison with RxJava

RxJava can also combine data streams using zip , but coroutines provide a more straightforward, less error‑prone syntax.

// RxJava version
private void assembleDataList(PlatformResponse response) {
    Observable
> localStaticData = getLocalStaticData();
    Observable
> dynamicData = getDynamicData(response);
    Observable
> observable = Observable.zip(localStaticData, dynamicData, (a,b) -> combine(a,b));
    subscribe(observable, callback);
}

Coroutines are lightweight, have higher execution efficiency, and simplify asynchronous code, while RxJava offers powerful operators but has a steeper learning curve.

Choosing Between Coroutines and RxJava

If a project already heavily uses RxJava, migration may not be necessary; otherwise, Kotlin coroutines are a modern, concise alternative for Android development.

AndroidconcurrencyKotlinasynccoroutinesRxJavawithContext
JD Retail Technology
Written by

JD Retail Technology

Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.

0 followers
Reader feedback

How this landed with the community

login 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.