ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Top 10 Coroutine Mistakes We All Have Made as Android Developers

Dobri Kostadinov
ProAndroidDev
Published in
5 min readNov 3, 2024
This image was generated with the assistance of AI

Introduction

1. Blocking the Main Thread

The Mistake:

Why It Happens:

How to Avoid It:

// Wrong
GlobalScope.launch {
// Long-running task
}

// Correct
GlobalScope.launch(Dispatchers.IO) {
// Long-running task
}

2. Ignoring Coroutine Scope Hierarchy

The Mistake:

Why It Happens:

How to Avoid It:

// In a ViewModel
viewModelScope.launch {
// Coroutine work
}

3. Mishandling Exception Propagation

The Mistake:

Why It Happens:

How to Avoid It:

viewModelScope.launch {
try {
// Suspended function that might throw an exception
} catch (e: Exception) {
if (e !is CancellationException) {
// Handle exception
} else {
throw e // Rethrow to respect cancellation
}
}
}
val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
if (throwable !is CancellationException) {
// Handle unhandled exception
}
}

viewModelScope.launch(exceptionHandler) {
// Suspended function that might throw an exception
}

4. Using the Wrong Coroutine Builder

The Mistake:

Why It Happens:

How to Avoid It:

// Using async when you need a result
val deferredResult = async {
computeValue()
}
val result = deferredResult.await()

5. Overusing GlobalScope

The Mistake:

Why It Happens:

How to Avoid It:

6. Not Considering Thread Safety

The Mistake:

Why It Happens:

How to Avoid It:

val mutex = Mutex()
var sharedResource = 0

coroutineScope.launch {
mutex.withLock {
sharedResource++
}
}

7. Forgetting to Cancel Coroutines

The Mistake:

Why It Happens:

How to Avoid It:

val job = CoroutineScope(Dispatchers.IO).launch {
// Work
}

// Cancel when done
job.cancel()

8. Blocking Inside Coroutines

The Mistake:

Why It Happens:

How to Avoid It:

// Wrong
launch(Dispatchers.IO) {
Thread.sleep(1000)
}

// Correct
launch(Dispatchers.IO) {
delay(1000)
}

9. Misusing withContext

The Mistake:

Why It Happens:

How to Avoid It:

// Correct usage
val result = withContext(Dispatchers.IO) {
// Perform I/O operation
}

10. Not Testing Coroutines Properly

The Mistake:

Why It Happens:

How to Avoid It:

@Test
fun testCoroutine() = runTest {
val result = mySuspendingFunction()
assertEquals(expectedResult, result)
}

Conclusion

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Written by Dobri Kostadinov

15+ years in native Android dev (Java, Kotlin). Expert in developing beautiful android native apps.

Responses (4)

Write a response