Skip to content Skip to footer

Barcode Scanner with Google ML Kit

What are Google ML Kit and CameraX Library?

ML Kit is a powerful Machine Learning library optimized for mobile applications. There are a lot of APIs in this library like barcode scanning, face detection, image labeling, text recognition, etc. With ML Kit’s barcode scanning API, we can read data encoded using most standard barcode formats. Barcode scanning happens on the device and doesn’t require a network connection.

CameraX is a Jetpack support library, built to help you make camera app development easier. It provides a consistent and easy-to-use API surface that works across most Android devices, with backward compatibility to Android 5.0 (API level 21). For example, it calculates the rotation value of the scanned image. So we don’t have to do anything for this calculation.

Let’s start!

1- Dependencies and Manifest

  • Add the dependencies into application-level build.gradle file:
// Barcode scanning API
implementation ''

def camerax_version = "1.0.1"
// CameraX core library using camera2 implementation
implementation "$camerax_version"
// CameraX Lifecycle Library
implementation "$camerax_version"
// CameraX View class
implementation ""
  • Add the CAMERA permission into AndroidManifest.xml file:
<uses-permission android:name="android.permission.CAMERA" />

2- ImageAnalyzer Class

  • Create a class that implements ImageAnalysis.Analyzer the interface. This interface is used to receive images and perform custom processing by implementing analyze(ImageProxy)functions. So we can do all the scanning logic here:

That’s it! Let’s explain this code block:

  • First, we created scanBarcode function that takes ImageProxy parameter. Then we passed image and rotationDegrees properties of ImageProxy to inputImage value. “rotationDegree” is calculated automatically by CameraX.
  • We can choose which barcode type to be scanned. In this example only “FORMAT_QR_CODE” is added but there are a lot of supported types. Actually this step is optional so if we don’t add any type, the Scanner scan for all barcode types. But choosing certain types is more optimized and faster.
  • In the last step, we passed addOnCompleteListener to scanner.process(inputImage). It is important to call the image.close() method once the analysis is completed. This will free the analysis queue for other images to be processed. “addOnCompleteListener” gives a barcode list so if task is successful taking first item of the list will be enough. “barcode.rawValue” is our scanned barcode value and we can pass this to a listener to use in our Activity/Fragment.

Note: Instead of if/else block you can use “addOnSuccessListener” and “addOnFailureListener”. They will give the same result. You can choose whatever you want.

3- PreviewView

PreviewView is responsible for displaying the camera preview on the screen.

        android:layout_height="match_parent" />

4- Camera Permissions

In Fragment, we need to take camera permission.

5- Setup Preview

  • First, add these values ​​at the top of the class:
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
private val cameraExecutor = Executors.newSingleThreadExecutor()
private var imageAnalyzer: ImageAnalyzer? = null

cameraProvideFuture will bind the camera lifecycle to the application.

cameraExecutor will be responsible for tracking the tasks generated by the camera.

  • Create a function that bind Preview use case with PreviewView we defined in our XML(binding.previewView).
  • First, we configured camera settings and bind our previewView. Then added ideal target resolution values.
  • setAnalyzer()” method of ImageAnalyzer is called here and required parameters are added.
  • cameraProvider.bindToLifeCycle()” method binds preview to the lifecycle of our Fragment/Activity.

6- Scanning Barcode

Almost done! This is the last step. We can create a function that invokes the scanner listener we create in ImageAnalyzer class and configure cameraProvideFuture:

We called “bindPreview()” function in “cameraProviderFuture.addListener” and passed “cameraProviderFuture.get()” parameter. In “scannerListener” we display a toast message that shows barcode value.

Note: Don’t forget to add these to “onDestroyView()”:

override fun onDestroyView() {
    if (::cameraProviderFuture.isInitialized) {

Leave a comment