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