Use case: I have a lot of operations that I want to happen asynchronously from the main thread but also in parallel with each other.
val scope = CoroutineScope(Dispatchers.IO)
val items = // List of items to do something.
scope.launch {
items.forEach { item ->
scope.launch {
if (itemFailsValidation(item)) {
// Here I want to skip this item but continue the forEach loop.
return@launch // "There is more than one label with such a name in this" scope"
}
doSomethingThatMightTakeABit(item)
}
}
}
If I try to add a label, like inner@scope.launch
, editor says "Label is redundant, because it can not be referenced in either ''break'', ''continue'', or ''return'' expression"
Does anyone know a good way of doing this?
If we need to return from a lambda expression, we have to label it and qualify the return. For your case to return from inner coroutine:
scope.launch {
items.forEach { item ->
scope.launch innerScope@ {
if (itemFailsValidation(item)) {
return@innerScope
}
doSomethingThatMightTakeABit(item)
}
}
}
But we can simplify your case and rewrite code without using a label:
scope.launch {
items.forEach { item ->
if (!itemFailsValidation(item)) {
scope.launch { doSomethingThatMightTakeABit(item) }
}
}
}
// OR
items.forEach { item ->
if (!itemFailsValidation(item)) {
scope.launch { doSomethingThatMightTakeABit(item) }
}
}
If you want to wait for all coroutines to finish and do something on UI thread:
scope.launch(Dispatchers.Main) {
processItemsInBackground()
// update UI after processing is finished
}
suspend fun processItemsInBackground() = withContext(Dispatchers.IO) {
// withContext waits for all children coroutines
items.forEach { item ->
if (!itemFailsValidation(item)) {
launch { doSomethingThatMightTakeABit(item) }
}
}
}