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()
时,就好像你只是直接调用了里面的代码。所以你可以删除你似乎不需要的async
、await
和coroutineScope
。
不需要 var x = null
后跟 x = something
- 只需立即初始化变量即可。另外,如果以后不改的话,可以用val
代替。
您可能想要的是将 callback-based API 包装到一个挂起函数中。你可以用 suspendCoroutine
或 suspendCancellableCoroutine 来做(取决于你调用的 API 是否可取消 and/or 如果你希望你的函数无论如何都是可取消的)。
该文档提供了有关如何执行此操作的示例。
我是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()
时,就好像你只是直接调用了里面的代码。所以你可以删除你似乎不需要的async
、await
和coroutineScope
。不需要
var x = null
后跟x = something
- 只需立即初始化变量即可。另外,如果以后不改的话,可以用val
代替。
您可能想要的是将 callback-based API 包装到一个挂起函数中。你可以用 suspendCoroutine
或 suspendCancellableCoroutine 来做(取决于你调用的 API 是否可取消 and/or 如果你希望你的函数无论如何都是可取消的)。
该文档提供了有关如何执行此操作的示例。