'Is there a way how I can run code on multiple threads so it gets executed faster and then wait for all of them to complete?

I have 2 functions, I need the first one to be completed first and then the second, but running it on one thread took a long time so I tried running it like with CoroutineScope, but the second function executes even if not all images are downloaded.

downloadSkillsImages(context)      
addSkillsToDB()
private suspend fun downloadSkillsImages(context: Context) {
        for (i in 0 until skills.size) {
            CoroutineScope(IO).launch {
                try {
                    val url = fbStorage.reference.child("skillImagesMini").child("${skills[i].skillId}.jpg").downloadUrl.await()
                    skills[i].skillImage = getBitmapFromUri(url, context)
                }catch (e: Exception){
                    //image not found, nothing happens
                }
            }
        }
    }


Solution 1:[1]

This is what the coroutineScope scope function is for. It waits for all its children coroutines to finish.

private suspend fun downloadSkillsImages(context: Context) = coroutineScope {
    for (i in skills.indices) {
        launch(Dispatchers.IO) {
            try {
                val url = fbStorage.reference.child("skillImagesMini").child("${skills[i].skillId}.jpg").downloadUrl.await()
                skills[i].skillImage = getBitmapFromUri(url, context)
            } catch (e: Exception){
                //image not found, nothing happens
            }
        }
    }
}

Note, you only need to specify Dispatchers.IO if getBitmapFromUri is a blocking function. If it's a suspend function, then nothing in this child coroutine is blocking, so it wouldn't matter what dispatcher is used to call it.

Since you want your coroutines to all finish and silently ignore the ones that fail, you can simplify this by using supervisorScope instead of coroutineScope so you don't need try/catch. supervisorScope will complete successfully even if some of its children fail.

private suspend fun downloadSkillsImages(context: Context) = supervisorScope {
    for (i in skills.indices) {
        launch(Dispatchers.IO) {
            val url = fbStorage.reference.child("skillImagesMini").child("${skills[i].skillId}.jpg").downloadUrl.await()
            skills[i].skillImage = getBitmapFromUri(url, context)
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tenfour04