【问题标题】:How to return an int from CoroutineScope Kotlin?如何从 CoroutineScope Kotlin 返回一个 int?
【发布时间】:2021-04-10 11:33:55
【问题描述】:

我是 android 开发的新手,我不知道如何从 Firestore 中返回 Coroutine 中的 int...

这是我的功能代码:

    fun getSharesNumber(context: Context, name:String) = CoroutineScope(Dispatchers.IO).launch {
        try {
            var trade1:Trade
            var sharesNumber:Int
            tradesCollectionRef.document(name)
                .get()
                .addOnSuccessListener {
                        trade1 = it.toObject(Trade::class.java)!!
                            sharesNumber = trade1.shares
                    }.await()
        }catch (e:Exception){
            withContext(Dispatchers.Main){
                Toast.makeText(context,"$e",Toast.LENGTH_LONG).show()
        }
    }
}

请帮我在调用这个函数时返回shareNumber。

【问题讨论】:

  • 除非你使用runBlocking,否则你不能从一个协程返回一个值到一个非挂起函数,这会触发一个ANR错误并且不应该在UI代码中使用。如果需要返回值,请创建函数suspend,并使用CoroutineScope/launchwithContext insted 来返回值。
  • @Tenfour04 请将此信息添加为答案,因为它描述并提供了非常好的反馈。
  • @Tenfour04 您能否编辑我的代码以更正答案中的一个?谢谢

标签: android function kotlin google-cloud-firestore kotlin-coroutines


【解决方案1】:

除非您使用runBlocking,否则您不能将协程中的值返回到非挂起函数,这可能会触发 ANR 错误,并且不应该在 UI 代码中使用。如果您需要返回值,则将函数挂起,并使用 withContext 而不是 CoroutineScope/launch 来返回必须在后台线程上计算的值。

当您使用的库已经提供了await() 挂起功能时,您不需要使用suspendCoroutine。由于await是一个挂起函数,你也不必用特定的调度器调用它,也不需要处理回调,所以你的代码可以变成:

suspend fun getSharesNumber(context: Context, name:String): Int {
    return try {
        tradesCollectionRef.document(name).get().await()
            .toObject(Trade::class.java)?.shares
            ?: error("Document $name doesn't exist.")
    } catch (e:Exception){
        withContext(Dispatchers.Main){
            Toast.makeText(context, "$e", Toast.LENGTH_LONG).show()
        }
        -1
    }
}

如果失败,它会返回 -1。或者,您可以让它抛出异常并在更高的位置捕获它。不过,如果失败而不是抛出,返回 null 会更符合 Kotlin 的习惯。由于我不使用 Firestore,因此我没有对此进行测试,因此语法可能会略有偏差。

【讨论】:

  • 谢谢你的回答,我在stackoverflow上搜索了很多,但没有找到一个很好的例子。现在我可以理解如何从协程返回一个值,即使我做的有点不同。感谢您的帮助!
【解决方案2】:

你需要使用suspendCoroutine函数,看看能不能满足你的需求

    suspend fun getSharesNumber(context: Context, name:String): Int {
        return suspendCoroutine {
            try {
                var trade1:Trade
                var sharesNumber:Int
                tradesCollectionRef.document(name)
                        .get()
                        .addOnSuccessListener {
                            trade1 = it.toObject(Trade::class.java)!!
                            sharesNumber = trade1.shares

                            // return int
                            it.resume(sharesNumber)

                        }.await()
            }catch (e:Exception){
                e.printStackTrace()
                it.resumeWithException(e)
            }
        }
    }

【讨论】:

  • await() 已经可用时,为什么还要使用suspendCoroutineawait()函数的存在使得Task类协程兼容,无需进入回调地狱。
  • @Tenfour04 是的,你说的很有道理,谢谢你的回答,我看了你的回答,你的方法很好
猜你喜欢
  • 2021-10-18
  • 2020-04-09
  • 2011-06-21
  • 1970-01-01
  • 2014-06-28
  • 1970-01-01
  • 2015-04-13
  • 2020-10-31
  • 1970-01-01
相关资源
最近更新 更多