fun完成后从Coroutine获取具体值

Get specific value from Coroutine after the fun is completed

我是kotlin初学者,第一次使用协程是在android。

我想在async调用完成后获取classification的值,并将结果传递给fragment,其中这个函数存在于非activity class .

我编写了以下函数,但它 return 第一次单击按钮时是一个空字符串,第二次单击时 return 是值。

你能帮帮我吗?

片段中的调用:

runBlocking{
imgResultTextView.setText(imageClassificationBean.imageClassification())}

乐趣在非activity class:

 suspend fun imageClassification(bitmap: Bitmap?): String = coroutineScope {
     val result = async {
         //ML process (image classification)
         var imageLabeler: ImageLabeler? = null
         imageLabeler = ImageLabeling.getClient(
             ImageLabelerOptions.Builder()
                 .setConfidenceThreshold(0.7f)
                 .build()
         )

         val inputImage = InputImage.fromBitmap(bitmap, 0)
         imageLabeler.process(inputImage)
             .addOnSuccessListener(OnSuccessListener { imageLabels: List<ImageLabel> ->
                 Log.i("lolo", "percentageDeferred: 2 "+ imageLabels)
                 val sb = StringBuilder()
                 for (label in imageLabels) {
                     sb.append(label.text).append(": ").append(label.confidence).append("\n")
                handleResult(sb.toString())
                 }
                 if (imageLabels.isEmpty()) {
                     classication = "Could not classify!!"
                 } else {
                     classication = sb.toString()
                 }
             }).addOnFailureListener(OnFailureListener { e: Exception ->
                 e.printStackTrace()
            handleResult("error")
             })
     }
     result.await()
     result.getCompleted()
         
     return@coroutineScope classication
}

我希望结果显示在第一次单击按钮的片段的文本视图中(class化值)。

这里的问题是您没有等待实际的异步操作(callback-based)。您将其包装在不必要的 async 中,然后 await,但基础操作 (imageLabeler.process()) 在 async 块中仍然是异步的,没有任何东西等待它。

以下是关于您的代码的几件事:

  • async { ... } 之后立即使用 await() 违背了 async 的目的。使用 async 的目的是 运行 块内的任何内容与块外(之后)的内容同时发生,直到 await() 它。当你立即 await() 时,就好像你只是直接调用了里面的代码。所以你可以删除你似乎不需要的asyncawaitcoroutineScope

  • 不需要 var x = null 后跟 x = something - 只需立即初始化变量即可。另外,如果以后不改的话,可以用val代替。

您可能想要的是将 callback-based API 包装到一个挂起函数中。你可以用 suspendCoroutinesuspendCancellableCoroutine 来做(取决于你调用的 API 是否可取消 and/or 如果你希望你的函数无论如何都是可取消的)。

该文档提供了有关如何执行此操作的示例。