Android CameraX Overview

Filed Under: Android

In this tutorial, we’ll be discussing at length upon Android CameraX API. CameraX was one of the popular releases in Google IO 2019. Let’s see what it has in store for us.

What is Android CameraX?

Developing Camera Apps has always been hard. Getting a hold of the Camera APIs was never easy.

Hence, CameraX which is introduced in the Jetpack Support Library is a respite. It aims at making the development process easier.

Besides API complexity, while developing camera applications, we had to tackle a lot of scenarios such as:

  • OS Versions
  • Device Model specifications – Android Market is fragmented and has a vast variety of device configurations. Same Application can behave differently on different phones especially Samsung.

In this regards, CameraX strives to be more consistent across devices. CameraX basically uses Camera2 API under the hood but with a better implementation process. It is backward compatible until Android Lollipop (SDK 21).

CameraX provides the same consistency as the deprecated Camera 1 API by including the Camera 2 Legacy Layer.

How did Google do this?

Using an Automated CameraX test lab with a number of devices from various manufacturers.

CameraX has tackled the following issues as per Google IO 2019.

Android Camerax Fixes Google Source

Source: Google IO 2019

Android CameraX : Abstracting Camera2 API

Camera2 API provided us a lot of fine grain control over the sensors. More so, it required a lot of boilerplate code. It required communication with the HAL (Hardware Acceleration Layer) in order to access the hardware and drivers of the camera.

What CameraX essentially does is abstract all of this.

Hence CameraX provides ease of use, thanks to more readability and less boilerplate code.

Android CameraX : Use Cases

CameraX has come up with a use case-based approach to focus on the task you need to get done instead of spending time managing device-specific configurations.

The three core use cases are:

  • Preview – What you see. The Camera Feed.
  • Image Analysis – What you do. Processing the Camera Feed.
  • Image Capture – What you keep. Capturing the photo/video.

Android CameraX Extensions

Extensions basically allow us to use device-native camera features directly in our custom camera application with just a few lines of code.

Features like portrait mode, depth, Bokeh effect if supported by the device can be integrated into the use cases easily.

CameraX is lifecycle aware. So instead of starting and stopping the camera preview and other use cases in onResume() and onPause(), we can do that, using CameraX.bindToLifecycle().

Enough talk. Let’s deep dive into CameraX code now.

In the section below, we’ll be implementing two use cases – Preview and Image Capture. Image Analyzer would be covered in a separate tutorial.

CameraX Example Project Structure

Android Camerax Project Structure

Android Camerax Project Structure

CameraX Implementation Code

Let’s set up the build.gradle first:

implementation 'androidx.appcompat:appcompat:1.1.0-alpha03'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
def cameraxVersion = "1.0.0-alpha02"
implementation "${cameraxVersion}"
implementation "${cameraxVersion}"

We need to add the permissions for Camera and External Storage in the AndroidManifest.xml file.

The code for the activity_main.xml layout is given below:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=""

        app:layout_constraintEnd_toEndOf="parent" />

        app:layout_constraintStart_toStartOf="parent" />


The code for the class is given below.

package com.journaldev.androidcamerax;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;

import android.os.Bundle;
import android.os.Environment;
import android.util.Rational;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;


public class MainActivity extends AppCompatActivity {

    private int REQUEST_CODE_PERMISSIONS = 101;
    private final String[] REQUIRED_PERMISSIONS = new String[]{"android.permission.CAMERA", "android.permission.WRITE_EXTERNAL_STORAGE"};
    TextureView textureView;

    protected void onCreate(Bundle savedInstanceState) {

        textureView = findViewById(;

            startCamera(); //start camera if permission has been granted by user
        } else{
            ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);

    private void startCamera() {


        Rational aspectRatio = new Rational (textureView.getWidth(), textureView.getHeight());
        Size screen = new Size(textureView.getWidth(), textureView.getHeight()); //size of the screen

        PreviewConfig pConfig = new PreviewConfig.Builder().setTargetAspectRatio(aspectRatio).setTargetResolution(screen).build();
        Preview preview = new Preview(pConfig);

                new Preview.OnPreviewOutputUpdateListener() {
                    //to update the surface texture we  have to destroy it first then re-add it
                    public void onUpdated(Preview.PreviewOutput output){
                        ViewGroup parent = (ViewGroup) textureView.getParent();
                        parent.addView(textureView, 0);


        ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
        final ImageCapture imgCap = new ImageCapture(imageCaptureConfig);

        findViewById( View.OnClickListener() {
            public void onClick(View v) {
                File file = new File(Environment.getExternalStorageDirectory() + "/" + System.currentTimeMillis() + ".png");
                imgCap.takePicture(file, new ImageCapture.OnImageSavedListener() {
                    public void onImageSaved(@NonNull File file) {
                        String msg = "Pic captured at " + file.getAbsolutePath();
                        Toast.makeText(getBaseContext(), msg,Toast.LENGTH_LONG).show();

                    public void onError(@NonNull ImageCapture.UseCaseError useCaseError, @NonNull String message, @Nullable Throwable cause) {
                        String msg = "Pic capture failed : " + message;
                        Toast.makeText(getBaseContext(), msg,Toast.LENGTH_LONG).show();
                        if(cause != null){

        //bind to lifecycle:
        CameraX.bindToLifecycle((LifecycleOwner)this, preview, imgCap);

    private void updateTransform(){
        Matrix mx = new Matrix();
        float w = textureView.getMeasuredWidth();
        float h = textureView.getMeasuredHeight();

        float cX = w / 2f;
        float cY = h / 2f;

        int rotationDgr;
        int rotation = (int)textureView.getRotation();

            case Surface.ROTATION_0:
                rotationDgr = 0;
            case Surface.ROTATION_90:
                rotationDgr = 90;
            case Surface.ROTATION_180:
                rotationDgr = 180;
            case Surface.ROTATION_270:
                rotationDgr = 270;

        mx.postRotate((float)rotationDgr, cX, cY);

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        if(requestCode == REQUEST_CODE_PERMISSIONS){
            } else{
                Toast.makeText(this, "Permissions not granted by the user.", Toast.LENGTH_SHORT).show();

    private boolean allPermissionsGranted(){

        for(String permission : REQUIRED_PERMISSIONS){
            if(ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED){
                return false;
        return true;

PreviewConfig is where we configure the preview which is the live camera feed.

In the builder, we can set stuff like Aspect Ratios, Lens front or back, and target resolution.

The Preview is displayed on a TextureView.

ImageCaptureConfiguration.Builder() is configuration for image when captured. We set different configuration like MIN_LATENCY or MAX_QUALITY.

An output screenshot of the application in action is given below:

Android Camerax Output

Android Camerax Output

That brings an end to this tutorial. You can download the project from the link below or view the full source code from the Github Link provided underneath.


  1. Pawan says:

    How can i set different size to preview dynamically

  2. monica says:

    you have commented a line for front camera but when i uncomment that line app start force close

    1. Jerry Naidoo says:

      ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
      .setLensFacing(CameraX.LensFacing.FRONT) //add this part in

      Thanks to this solution :

  3. nitin says:

    this code is not working on One Plus 3T , if you guys have any solution please help

  4. Raj says:

    Its working great man!! Awesome

  5. kalyani says:

    Code not working on android 10(Q) version. Error throwing pic captured failed:Failed to write or close the file

    1. Arjis says:

      You probably haven’t set read and write to external storage permissions in your manifest file. Your app must have Camera, Read& Write to external storage or it will crash or throw some error as in this case.

    2. Ismail says:

      In Android 10 and above,

      add android:requestLegacyExternalStorage=”true” in the application tag in AndroidManifest.xml

  6. SmugDoodleBug says:

    Is anyone else having an issue where the TextureView isn’t rotating properly on device reorientation?

  7. buddudevelopers says:

    you could do this or you could just use an intent so the built-in camera app does the work for you.

    1. Anupam says:

      Custom Cameras allow you lots of customizations. Face Detection and other video processing stuff. You can even customise ISO, Shutter and Exposure of the camera.

      1. Keith Matthews says:

        Please, how can we customize the ISO, Shutter and Exposure? I’ve searching and I have come up with very little.

        1. Anupam says:

          CameraX has recently moved to the beta phase after being in the alpha phase for a while. Lots of features yet to be implemented.

  8. Hegde says:

    Good one,
    but the Preview camera window ‘s width is stretched. tried different ways to set width and height of texture view and aspect ratio but wasn’t much helpfull . I could avoid stretching but preview quality got decreased

    suggest if have any solution


  9. Monique says:

    Hello! Thanks for the tutorial 馃檪
    I followed all the steps of the tutorial. The camera opens normally, but the app is not saving the pic. Even if all the permissions granted, it is not allowing to save the pic. This is the error:

    2019-07-05 00:45:11.710 28373-28373/com.example.pegadamonique W/System.err: /storage/emulated/0-1562298311316.png (Permission denied)
    2019-07-05 00:45:11.711 28373-28373/com.example.pegadamonique W/System.err: at Method)
    2019-07-05 00:45:11.711 28373-28373/com.example.pegadamonique W/System.err: at
    2019-07-05 00:45:11.711 28373-28373/com.example.pegadamonique W/System.err: at
    2019-07-05 00:45:11.711 28373-28373/com.example.pegadamonique W/System.err: at
    2019-07-05 00:45:11.711 28373-28373/com.example.pegadamonique W/System.err: at
    2019-07-05 00:45:11.711 28373-28373/com.example.pegadamonique W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(
    2019-07-05 00:45:11.711 28373-28373/com.example.pegadamonique W/System.err: at java.util.concurrent.ThreadPoolExecutor$
    2019-07-05 00:45:11.711 28373-28373/com.example.pegadamonique W/System.err: at

    1. Lugi says:

      He forgot to add the permissions on the AndroidManifest, this 2 lines and you will be ok

Comments are closed.

Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors