I am Implementing Barcode Scanning functionality in my Android App. its working great for basic QR Code or Barcode FORMAT-128. But its not Accurate for Barcode FORMAT-39. Sometimes its captured correct value and some times wrong value. (especially when barcode value contains repeated values like A00000190) below are codes i tried and respective scanned values.
- Barcode value : AA00000029001
scan results randomly picking one of the following : AA00000029001, AA000029001, A100029001, AA00029001 .. etc
below is my code snippet.
class MainActivity3 : AppCompatActivity(), BarcodeScannerListener {
companion object {
private const val CAMERA_REQUEST_CODE = 101
private const val TAG = "MAIN_ACTIVITY"
}
private lateinit var viewBinding: ActivityMain3Binding
private val executorService: ExecutorService by lazy {
Executors.newSingleThreadExecutor()
}
private val barcodeScanner by lazy {
BarcodeScanner(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityMain3Binding.inflate(layoutInflater)
setContentView(viewBinding.root)
setupCamera()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == CAMERA_REQUEST_CODE && isCameraPermissionGranted()) {
startCamera()
}
}
private fun setupCamera() {
if (isCameraPermissionGranted()) {
startCamera()
} else {
requestPermission()
}
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder().build().apply {
setSurfaceProvider(viewBinding.cameraPreview.surfaceProvider)
}
val imageAnalyzer = ImageAnalysis.Builder().build().apply {
setAnalyzer(executorService, getImageAnalyzerListener())
}
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
this,
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
imageAnalyzer
)
} catch (throwable: Throwable) {
Log.e(TAG, "Use case binding failed", throwable)
}
}, ContextCompat.getMainExecutor(this))
}
@SuppressLint("UnsafeOptInUsageError")
private fun getImageAnalyzerListener(): ImageAnalysis.Analyzer {
return ImageAnalysis.Analyzer { imageProxy ->
val image = imageProxy.image ?: return@Analyzer
val inputImage = InputImage.fromMediaImage(image, imageProxy.imageInfo.rotationDegrees)
barcodeScanner.scanImage(inputImage) {
imageProxy.close()
}
}
}
override fun onSuccessScan(result: List<Barcode>) {
result.forEachIndexed { index, barcode ->
Log.e("MainActivity3","Barcode value : ${barcode.rawValue}")
Toast.makeText(this, "Barcode value: ${barcode.rawValue}", Toast.LENGTH_SHORT).show()
}
}
override fun onScanFailed() {
Toast.makeText(this, "Fail", Toast.LENGTH_SHORT).show()
}
private fun isCameraPermissionGranted(): Boolean {
return ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
}
private fun requestPermission() {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA),
CAMERA_REQUEST_CODE)
}
override fun onDestroy() {
super.onDestroy()
barcodeScanner.closeScanner()
executorService.shutdown()
}
}
Scanner Functionality :
class BarcodeScanner(private val barcodeScannerListener: BarcodeScannerListener) {
private val barcodeScanner: BarcodeScanner by lazy {
constructBarcodeScanner()
}
private val executorService: ExecutorService by lazy {
Executors.newSingleThreadExecutor()
}
fun scanImage(inputImage: InputImage, onScanComplete: (() -> Unit)? = null) {
barcodeScanner.process(inputImage)
.addOnCompleteListener {
onScanComplete?.invoke()
}
.addOnSuccessListener {
barcodeScannerListener.onSuccessScan(it)
}
.addOnFailureListener {
Log.e("Scanner fail", "caused:", it)
barcodeScannerListener.onScanFailed()
}
}
fun closeScanner() {
barcodeScanner.close()
executorService.shutdown()
}
private fun constructBarcodeScanner(): BarcodeScanner {
val barcodeScannerOptions = BarcodeScannerOptions.Builder()
.setExecutor(executorService)
.setBarcodeFormats(
// Barcode.FORMAT_ALL_FORMATS,
Barcode.FORMAT_CODE_39
)
.build()
return BarcodeScanning.getClient(barcodeScannerOptions)
}
}
Below are Some other Barcodes I tested and scan results
- Barcode value : R000000590
scan results randomly picking one of the following : R000000590, R00000590, V00000590, 40000590, 200000590 .. etc
- Barcode value : ABC-1200000034
scan results randomly picking one of the following : ABC-1200000034, ABC-12000034, ABC-1200000034, BP712000034, BP-12000034, ABC712000034 .. etc
Can someone please help to resolve these Barcodes with format-39 issue. Other types like QR Code or format-128 are working fine.


The data is repeated because the analyzer reads the image more than once. The image must be closed when the reading is complete
Or try this and see the result: