I have the following piece of code that uses Camer...
# compose
v
I have the following piece of code that uses CameraX and MLKit along with Compose:
Copy code
@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:
Copy code
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:
Copy code
scanning
<barcode>
not scanning
<barcode>
Could you tell me what I am doing wrong? And why is it printing exactly twice?
🧵 1
z
Please keep long code snippets to the thread to keep the main channel readable.
âž• 1
I don’t think this is a compose issue, it looks like
MlKitAnalyzer
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.
v
Apologies for the long thread text content, I forgot about moving the code snippets inside. You are right, I have solved the problem by wrapping the
MlKitAnalyzer
logic inside the
DisposableEffect