简体   繁体   中英

Kotlin Coroutine doesn't execute multiple suspend functions

I have a simple sequence of suspend functions (in Android Kotlin) which I want to run in sequence (once first is finished, then run second.)

I tried doing something which seamed reasonable like this:

class SomeService {

    init {

        GlobalScope.launch(Dispatchers.IO) {
            firstSuspendFunction()
            secondSuspendFunction()
        }
    }

}

However, only first one is run, second is never executed. Why is that so?

Edit: I tried to rule out some possible issues, and what seemed to worked was by completely emptying first function (empty body)!

The problem is that my firstFunction actually works, it has something like this:

private suspend fun firstSuspendFunction() {
    localProtoDataStore.preferences.collect {
        someDataList.addAll(it.preferenceData)
    }
}

Could it be that somehow launch never knowns if first suspend function has finished?

I assume that localProtoDataStore.preferences returns a Flow and it seems infinite, because it listens to the preferences changes. Calling collect() on such Flow will suspend any function until the collection is finished (but it never finished because the Flow is infinite) or CoroutineScope , which executed a coroutine, is canceled.

So to execute the second function you have a couple of options. For example you can get only one value from the Flow :

private suspend fun firstSuspendFunction() {
    localProtoDataStore.preferences.firstOrNull {
        someDataList.addAll(it.preferenceData)
    }
}

Or you can get rid of using Flow in the firstSuspendFunction() and just retrieve a current data in preferences:

private suspend fun firstSuspendFunction() {
    val data = localProtoDataStore.preferences.get() // I don't know the exact name of the function, but the idea is clear
    someDataList.addAll(data)
}

Or you can just launch another coroutine to collect data from the Flow :

scope.launch(Dispatchers.IO) {
    launch {
        firstSuspendFunction()
    }
    secondSuspendFunction()
}

Launch new Coroutine for each function call inside parent coroutine so that they can collect data from Flow individually without falling under suspension of parent coroutine . For example, in your case:

GlobalScope.launch(Dispatchers.IO) {
    launch { 
        firstSuspendFunction()
    }
    launch { 
        secondSuspendFunction()
    }
    ....
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM