Kotlin Coroutines with returning value

Kotlinkotlinx.coroutines

Kotlin Problem Overview


I want to create a coroutine method which has returning value.

For example)

fun funA() = async(CommonPool) {
	return 1
}

fun funB() = async(CommonPool) {
	return 2
}

fun sum() {
	launch {
		val total = funA().await() + funB().await()
	}
}

If I want to return total in sum method, how should I do?

like,

fun sum(): Int {
	launch {
		val total = funA().await() + funB().await()
	}	

	return total
}

Kotlin Solutions


Solution 1 - Kotlin

To return exactly Int, you need to get out of the coroutine world and that's what runBlocking is for:

fun sum(): Int = runBlocking {
    funA().await() + funB().await()
}

See Bridging blocking and non-blocking worlds in the coroutine guide, and Composing suspending functions for how to do it if you want to use sum inside coroutines.

Solution 2 - Kotlin

It may be late to answer this question but hopefully someone will find it useful. The code snippet below calculates sum of 3 values A + B + C. Each value is calculated independently in its own background thread in parallel and then all interim results consolidated into one final result and returned to the main thread to display it on a screen.

So it takes 5 seconds to calculate the final value (not 10 seconds = 2 + 3 + 5) and the result is 6 obviously and it's non-blocking, the main thread can handle other events while sum() execution is not complete.

suspend fun sum(scheduler: ThreadPoolExecutor): Int = coroutineScope {

    withContext(scheduler.asCoroutineDispatcher()) {
        val a = async { funA() }
        val b = async { funB() }
        val c = async { funC() }

        a.await() + b.await() + c.await()
    }
}

fun funA(): Int {
    Thread.sleep(2000L)
    return 1
}

fun funB(): Int {
    Thread.sleep(3000L)
    return 2
}

fun funC(): Int {
    Thread.sleep(5000L)
    return 3
}

class MainActivity : AppCompatActivity(), View.OnClickListener {
    private val tripletsPool = ThreadPoolExecutor(3, 3, 5L, TimeUnit.SECONDS, LinkedBlockingQueue())

   ...

    override fun onClick(view: View?) {
        if (view == null) {
            return
        }

        when (view.id) {
            R.id.calculate -> {
                GlobalScope.launch(Dispatchers.Main, CoroutineStart.DEFAULT) {
                    progressBar.visibility = View.VISIBLE
                    result.setText("${sum(tripletsPool)}")
                    progressBar.visibility = View.GONE
                }
            }
        }
    }
}

Solution 3 - Kotlin

Adding another way of achieving it.

fun sum(): Int {
    var sum: Int = 0
    runBlocking {
        val jobA = async { funA() }
        val jobB = async { funB() }
        runBlocking{
           sum = jobA.await() + jobB.await()
        }
    }
    return sum
}

suspend fun funA(): Int {
    return 1
}

suspend fun funB(): Int {
    return 2
}

Solution 4 - Kotlin

I edit your work, i change the funA and funB into a suspend function and i created a function for sum operator and i call on main function, this the example :

suspend fun funA(): Int{
    return 1
}

suspend fun funB(): Int {
    return 2
}
fun sum() = runBlocking{
    val resultSum = async { funA.await() + funB.await() }
    return resultSum
}

fun main() = runBlocking{
    val result = async { sum() }
    println("Your result: ${result.await()}")
}

Hope it will help

Solution 5 - Kotlin

Here's another way to run funA() and funB() in parallel without using runBlocking.

fun funA() = CoroutineScope(Dispatchers.Default).async {
    delay(3000)
    return@async 1
}

fun funB() = CoroutineScope(Dispatchers.Default).async {
    delay(3000)
    return@async 2
}

fun sum() = CoroutineScope(Dispatchers.Default).async {
    val a = funA()
    val b = funB()
    return@async a.await() + b.await()
}

And if you want to run sum() without blocking the main thread,

CoroutineScope(Dispatchers.Default).launch { // Use Dispatchers.IO for database or file I/O
    measureTimeMillis {
        Log.d("TAG", "sum=${sum().await()}")
    }.also {
        Log.d("TAG", "Completed in $it ms")
    }
}

Solution 6 - Kotlin

Here is the way I did it, to return a Boolean value when trying to delete a phone number from my Room database. You can use the same pattern for what you are trying to accomplish. In my view model:

private var parentJob = Job()
private val coroutineContext: CoroutineContext get() = parentJob + Dispatchers.Main
private val scope = CoroutineScope(coroutineContext)

suspend fun removePhoneNumber(emailSets: EmailSets, personDetails: PersonDetails) : Boolean  {
    var successReturn = false
    scope.async(Dispatchers.IO) {
        val success = async {removePhoneNumbersAsync(emailSets,personDetails)}
        successReturn = success.await()

    }
    return successReturn
}

fun removePhoneNumbersAsync(emailSets: EmailSets, personDetails : PersonDetails):Boolean {
    var success = false
    try {
        val emailAddressContact = EmailAddressContact(emailSets.databaseId, personDetails.id, personDetails.active)
        repository.deleteEmailAddressContact(emailAddressContact)
        val contact = Contact(personDetails.id, personDetails.personName, personDetails.personPhoneNumber, 0)  
        repository.deleteContact(contact)
        success = true
    } catch (exception: Exception) {
        Timber.e(exception)
    }
    return success
}

In my Activity:

runBlocking {
    if (v.tag != null) {
            val personDetails = v.tag as PersonDetails
            val success  = viewModel.removePhoneNumber(emailSets,personDetails)
            if (success) {
                val parentView = v.parent as View
                (parentView as? TableRow)?.visibility = View.GONE
                val parentViewTable = parentView.parent as ViewGroup
                (parentViewTable as? TableLayout)
                parentViewTable.removeView(parentView)
            }
     }

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionExpert wanna beView Question on Stackoverflow
Solution 1 - KotlinAlexey RomanovView Answer on Stackoverflow
Solution 2 - KotlinAleksei MulinView Answer on Stackoverflow
Solution 3 - KotlinSahil ChhabraView Answer on Stackoverflow
Solution 4 - KotlinCevin WaysView Answer on Stackoverflow
Solution 5 - KotlinJoonsooView Answer on Stackoverflow
Solution 6 - KotlinKristy WelshView Answer on Stackoverflow