在 kotlin 协程中实现 async-await()

Implementing async- await() in kotlin coroutine

我创建了如下函数:

fun getPercentage(id:String): String {
    var percentage=""
    scope.launch {
        percentage=repo.getPercentage(id)?.get(0)?.percent.toString()
        Log.e("$$$ value >>","$$$ value >>"+percentage)
    }
    Log.e("$$$ value outside >>","$$$ value >>"+percentage)
    return percenatge
}

在这里,我不能return使用变量更新值:百分比。

我得到的日志如下:

$$$ value outside >> 
$$$ value >> 50

表示我无法 return 最新值。流程出了点问题。

有人建议我使用 async{} 和 await()。但我不知道这对这里有什么帮助?

请指导。谢谢

launch函数在后台启动协程,然后继续。因此,您的“外部”代码在“内部”协程完成之前 运行。

使用协程中的async function instead to return a Deferred值:

fun getPercentage(id:String): Deferred<String> {
    return scope.async {
        percentage=repo.getPercentage(id)?.get(0)?.percent.toString()
        Log.e("$$$ value >>","$$$ value >>"+percentage)
    }
}

当然要注意的是,你更有可能想把getPercentage做成一个挂起函数,然后直接调用await

suspend fun getPercentage(id:String): String {
    val percentageDeferred = scope.async {
        percentage=repo.getPercentage(id)?.get(0)?.percent.toString()
        Log.e("$$$ value >>","$$$ value >>"+percentage)
    }
    val percentage = percentageDeferred.await()
    Log.e("$$$ value outside >>","$$$ value >>"+percentage)
    return percentage    
}

您也可能想在 await 之前执行其他操作,否则您最好也将 repo.getPercentage 设为挂起函数,然后直接调用它:

suspend fun getPercentage(id:String): String {
    // if repo.getPercentage is a suspend function, this call suspends
    // like the await in the previous example
    val percentage = repo.getPercentage(id)?.get(0)?.percent.toString()
    Log.e("$$$ value outside >>","$$$ value >>"+percentage)
    return percentage    
}

请参阅 Kotlin 文档中的 Concurrent using async

我认为您不一定需要在这种情况下使用异步,尤其是。您只需要知道 launch { ... } 中的任何内容都是异步执行的。所以到 getPercentage returns 时,您的协程可能还没有启动。

记住这一点,我相信您可能想要更改代码的工作方式。在不更改签名的情况下使 fun getPercentage(id: String): String 工作的唯一方法是将 scope.launch { ... } 替换为 scope.runBlocking { ... },但您可能不想这样做,因为它会阻塞您的线程。

相反,您可以将 getPercentage 更改为 suspend 方法:

suspend fun getPercentage(id: String): String {
    return repo.getPercentage(id)?.get(0)?.percent.toString()
}

但是,suspend 方法只能从协程内部调用。所以你需要这样称呼它:

scope.launch {
    val percentage = getPercentage("some ID")
    // Now you can use `percentage` for whatever you need.
}