Vladimir
07/11/2024, 5:59 PM@Composable
fun QRScannerCameraScreen(
modifier: Modifier = Modifier,
handleScannedBarcode: (barcode: String) -> Unit,
isScanning: Boolean
) {
if (isScanning) {
println("scanning")
val context: Context = LocalContext.current
val previewView: PreviewView = remember { PreviewView(context) }
val cameraController: LifecycleCameraController =
remember { LifecycleCameraController(context) }
val lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current
cameraController.bindToLifecycle(lifecycleOwner)
cameraController.cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
previewView.controller = cameraController
val cameraExecutor = remember { Executors.newSingleThreadExecutor() }
val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.FORMAT_QR_CODE,
Barcode.FORMAT_EAN_13,
Barcode.FORMAT_CODE_128,
Barcode.FORMAT_CODE_39,
Barcode.FORMAT_PDF417,
Barcode.FORMAT_DATA_MATRIX
)
.build()
val barcodeScanner = BarcodeScanning.getClient(options)
AndroidView(
factory = {
previewView.apply {
clipToOutline = true
}
cameraController.setImageAnalysisAnalyzer(
cameraExecutor,
MlKitAnalyzer(
listOf(barcodeScanner),
COORDINATE_SYSTEM_VIEW_REFERENCED,
ContextCompat.getMainExecutor(context)
) { result: MlKitAnalyzer.Result? ->
val barcodeResults = result?.getValue(barcodeScanner)
if (barcodeResults.isNullOrEmpty()) {
previewView.overlay.clear()
return@MlKitAnalyzer
}
val barcode = barcodeResults.first().rawValue as String
println(barcode)
previewView.overlay.clear()
handleScannedBarcode(barcode)
}
)
previewView
},
modifier = modifier
)
}
else {
println("not scanning")
Text("Not scanning")
}
}
handleScannedBarcode resides in my viewModel:
fun handleScannedBarcode(barcode: String) {
onIsScanningChange(false)
}
The idea is that the isScanning state is set to false as soon as the first barcode is scanned stopping the scanning immediately. It appears to be working, in that after the barcode is picked up the text Not scanning shows up. However, I have noticed that println(barcode) prints the barcode twice, indicating that the component is recomposed twice?
This is the System.out output:
scanning
<barcode>
not scanning
<barcode>
Could you tell me what I am doing wrong? And why is it printing exactly twice?Zach Klippenstein (he/him) [MOD]
07/11/2024, 9:10 PMZach Klippenstein (he/him) [MOD]
07/11/2024, 9:15 PMMlKitAnalyzer is calling that result handler lambda twice. Perhaps the image analyzer pipeline is not fully cancelled synchronously when the View is detached? You might try passing an onRelease function to AndroidView that explicitly tears down the image analyzer pipeline.Vladimir
07/12/2024, 5:11 PMMlKitAnalyzer logic inside the DisposableEffect