Kotlin Coroutines具有回归价值

时间:2017-11-01 13:19:02

标签: kotlin kotlinx.coroutines

我想创建一个具有返回值的协程方法。

例如)

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

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

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

如果我想以总和方式返回总数,我该怎么做?

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

    return total
}

6 个答案:

答案 0 :(得分:11)

要准确返回Int,您需要离开协程世界,这就是runBlocking的用途:

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

如果您想在协同程序中使用sum ,请参阅协程指南中的Bridging blocking and non-blocking worldsComposing suspending functions,了解如何操作。

答案 1 :(得分:2)

回答这个问题可能为时已晚,但希望有人会发现它有用。下面的代码段计算了3个值A + B + C的总和。每个值都是在其自己的后台线程中并行并行计算的,然后将所有中期结果合并为一个最终结果,并返回到主线程以在屏幕上显示。

因此,计算最终值需要5秒(而不是10秒= 2 + 3 + 5),结果显然是6,并且是非阻塞的,主线程可以处理其他事件,而sum()执行不是完成。

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
                }
            }
        }
    }
}

答案 2 :(得分:2)

添加另一种实现方法。

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
}

答案 3 :(得分:0)

这是我这样做的方法,当尝试从Room数据库中删除电话号码时返回一个布尔值。您可以为要完成的任务使用相同的模式。在我的视图模型中:

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
}

在我的活动中:

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)
            }
     }

}

答案 4 :(得分:0)

我编辑您的工作,将funA和funB更改为暂停函数,并为sum运算符创建了一个函数,然后调用main函数,此示例:

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()}")
}

希望这会有所帮助

答案 5 :(得分:0)

这是另一种无需使用funA()即可并行运行funB()runBlocking的方法。

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

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

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

如果您想运行sum()而不阻塞主线程,

CoroutineScope(Dispatchers.IO).launch {
    measureTimeMillis {
        Log.d("TAG", "sum=${sum().await()}")
    }.also {
        Log.d("TAG", "Completed in $it ms")
    }
}