Kushal
Kushal

Reputation: 8508

How to wait and properly return value from async coroutine

I'm calling a function (non-suspended) from a button click. I want to run a loop in function using async coroutine and return last computed value.

My code :

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    btnCount.setOnClickListener {

        var result = GlobalScope.async { dummyFoo() }
        runBlocking {
            Toast.makeText(this@MainActivity, result.await().toString(), Toast.LENGTH_LONG).show()
        }
    }
}

private fun dummyFoo() : Int {
    var result : Int = 0
    val waitFor = CoroutineScope(Dispatchers.IO).async {
        for (i in 1..20000) {
            result++
        }
        return@async result
    }

    return result
}

Output :

I'm getting 0 in Toast.

I want 20000 in Toast.

How can I make my code to wait until loop completion and result to become 20000 and output it?

Upvotes: 6

Views: 13713

Answers (3)

Marko Topolnik
Marko Topolnik

Reputation: 200256

It seems that you want to launch a CPU-intensive task off the GUI thread and then present the result in GUI. This is a basic use case of coroutines and it's solved as follows:

btnCount.setOnClickListener {
    GlobalScope.launch(Dispatchers.Main) {
        val result = withContext(Dispatchers.Default) {
            dummyFoo()
        }
        Toast.makeText(this@MainActivity, result.toString(), Toast.LENGTH_LONG).show()
    }
}

This goes with the usual warning that you should not launch coroutines in the global scope, instead create a scope for the activity in question. Otherwise these background tasks will hog the CPU even when the user switches away from your app.

Upvotes: 6

Dmitri
Dmitri

Reputation: 2982

Not sure I am seeing the purpose of this, but if that's what you want, replace Dispatchers.IO with Dispatchers.Unconfined

Upvotes: 1

Cuong Nguyen
Cuong Nguyen

Reputation: 1018

You should use await in dummyFoo()

private suspend fun dummyFoo() : Int {
    var result : Int = 0
    val waitFor = CoroutineScope(Dispatchers.IO).async {
        for (i in 1..20000) {
            result++
        }
        return@async result
    }
    waitFor.await()
    return result
}

Upvotes: 7

Related Questions