I am stuck on an attempt to write "idiomatic" Kotlin async code. I am trying to refactor a barcode scanner as a top/ package level function.
How could I make the thread wait for the scanner.process(image) to complete, and return the list of barcodes before continuing?
The code partially shows my "closest" attempt to solve the problem.
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()
}
prints
D/BAR One
D/BAR Three
D/BAR Two
and the inferred return type of scanBarcodes is Task<MutableListOf<Barcode>>
In Dart/ Flutter I would write something like <T> scanBarcodes() async {} and accordingly var codes = await ... to solve the problem. I suppose I could use val codes = runBlocking{...} to block the main thread while completing. However, this async pattern is apparently strongly discouraged in Kotlin.