G. *_*lly 3 android async-await kotlin kotlin-coroutines
我一直试图编写“惯用的”Kotlin 异步代码。我正在尝试将条形码扫描仪重构为顶级/包级功能。
如何让线程等待完成scanner.process(image),并在继续之前返回条形码列表?
该代码部分显示了我解决问题的“最接近”尝试。
package com.example.demo
import android.util.Log
import com.google.mlkit.vision.barcode.Barcode
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.common.InputImage
import kotlinx.coroutines.*
class BarcodeActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val scanButton = findViewById<Button>(...)
scanButton.setOnClickListener {
// Get Bitmap image
runBarcode(image)
}
}
// Member function, calling codes should return a list of barcodes
// after completing
fun runBarcode(image: InputImage) = runBlocking {
Log.d("BAR", "One")
val codes = async { scanBarcodes(image)}
Log.d("BAR", "Three")
}
}
// Package level function
suspend fun scanBarcodes(image: InputImage) = coroutineScope {
val scanner = BarcodeScanning.getClient()
val codes = async {
scanner.process(image)
.addOnSuccessListener { barcodes ->
val barcodeList = mutableListOf<Barcode>()
Log.d("BAR", "Two")
for (barcode in barcodes) {
barcodeList.add(barcode)
}
return@addOnSuccessListener
}
.addOnFailureListener {
Log.e("BAR", "Barcode scan failed")
}
}
codes.await()
}
Run Code Online (Sandbox Code Playgroud)
印刷
D/BAR One
D/BAR Three
D/BAR Two
Run Code Online (Sandbox Code Playgroud)
推断的返回类型scanBarcodes是Task<MutableListOf<Barcode>>
在 Dart/Flutter 中,我会编写类似的内容<T> scanBarcodes() async {}来var codes = await ...解决问题。我想我可以val codes = runBlocking{...}在完成时阻止主线程。然而, Kotlin显然强烈反对这种异步模式。
不要用于runBlocking此。它会阻塞您的主线程,从而在等待时冻结 UI(用户无法滚动、单击甚至导航离开您的应用程序)。它还会让您面临 ANR 崩溃的风险。您应该从点击侦听器启动一个协程,以便可以将此函数设为挂起函数。
要将回调用作挂起函数,通常您必须将其转换为使用 挂起的函数suspendCancellableCoroutine()。然而,Kotlin 协程库已经为您提供了这种情况下的Task.await()挂起函数。如果无法在您的项目中导入,请将此依赖项添加到您的 build.gradle 中:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.0"
Run Code Online (Sandbox Code Playgroud)
该await()函数返回任务的结果,或者如果任务失败,它会抛出异常,因此您应该将其包装在 try/catch 中,而不是使用成功和失败侦听器。
以下是修复代码的方法:
class BarcodeActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val scanButton = findViewById<Button>(...)
scanButton.setOnClickListener {
lifecycleScope.launch {
val barcodes = scanBarcodes(image)
// do something with returned barcodes or maybe show message if list empty
}
}
}
}
// Package level function
suspend fun scanBarcodes(image: InputImage): List<Barcode> {
return try {
BarcodeScanning.getClient()
.process(image)
.await()
} catch(e: Exception) {
Log.e("BAR", "Barcode scan failed")
emptyList() // Returns an empty list on failure, but you might want to handle it differently, like returning null.
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4033 次 |
| 最近记录: |