CameraX has released the 1.0 official version of the App involving the use of the camera, can make full use of the camera has a big difference, so it is necessary to understand and recognize the CameraX.

📑 Soon to learn

Create camera, shoot, and preview with the Jetpack component support library CameraX

⭕ requirements

CameraX is a Jetpack component support library that will help simplify the development of camera-related applications. It also provides a consistent and easy-to-use API for most Android devices, with backward compatibility to Android 5.0 (API level 21)

Therefore, when creating an Android application, mininumSDK needs to select 5.0

Prepend content

Take a photo with Intent

The easiest way to take a photo in your application is to use mediastore.action_image_capture, pass in the Intent and launch it

This will activate the system camera and provide the user with a full set of camera capabilities and at this point, if the user grants the user permission to take a photo, and they’re satisfied with the photo, we’ll be able toonActivityResultBy default, the photo taken is returned as a thumbnail, which can be obtained using the data key

Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
Copy the code

To get the full image, in the Intent that launched the camera, add the mediastore. EXTRA_OUTPUT parameter to the Intent and set the output URI of the file. The URI will store the full photo

After the storage of the complete picture path after the picture and SettingsThis storage setting has some limitations. For details, see the official operation on taking photos Photos | | Android Developers Android Developers (Google, cn)) These are some of the operations that we use in our daily life to get images from the camera. During development, we still had a lot of dirty code when using the API for Camera2, and CameraX came out as a Jetpack component from Google. To simplify Camera development, let’s see how to use CameraX

In actual combat

Create a project

Add and synchronize the CameraX dependency in the App module

Use PreviewView to implement the CameraX preview

1. Add a PreviewView to the layout file

Make changes in the layout file

Manifest states camera permissions
<uses-permission android:name="android.permission.CAMERA" />
Copy the code
Dynamically apply for camera permissions
/ / overwrite onRequestPermissionsResult () method
override fun onRequestPermissionsResult(
    requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    if (requestCode == REQUEST_CODE_PERMISSIONS) {
        if (allPermissionsGranted()) {
            startCamera()
        } else {
            Toast.makeText(this."Permission not granted by user",
                Toast.LENGTH_SHORT).show()
            finish()
        }
    }
Copy the code
2. Request ProcessCameraProvider

ProcessCameraProvider is a singleton that binds the camera’s lifecycle to any lifecycle holder in the application process. Because The cameraX has life cycle sensing, this saves our application the task of turning the camera on and off

val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
Copy the code
Check the availability of ProcessCameraProvider
cameraProviderFuture.addListener(Runnable {}, ContextCompat.getMainExecutor(this))
Copy the code
4. When ProcessCameraProvider is available, select the camera and bind the life cycle and use case
  • Create a Preview
  • Specify the camera you want
  • Bind the selected camera and any use case to the life cycle
  • willPreviewConnect to thePreviewView
 cameraProviderFuture.addListener(Runnable {
            // 1 Bind the Camera to the lifecycle holder
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get(a)// 2 Create Preview.
            val preview = Preview.Builder()
                .build()
                .also {
                    / / the preview link previewView
                    it.setSurfaceProvider(findViewById<PreviewView>(R.id.viewFinder).getSurfaceProvider())
                }

            //3 Specifies the camera required
            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

            try {
                // 4 Unbind before binding
                cameraProvider.unbindAll()

                // 5 Bind the user case and camera to the life cycle
                cameraProvider.bindToLifecycle(
                    this, cameraSelector, preview)

            } catch(exc: Exception) {
                Log.e(TAG, "Use case binding failed", exc)
            }

        }, ContextCompat.getMainExecutor(this))
Copy the code

rendering

This is a preview of the camera

CameraX photos

Configure the app to take pictures
  • Use ImageCapture.Builder to build ImageCapture
  • Bind the user case and camera to the life cycle by adding an imageCapture
cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
Copy the code
Taking pictures
  • Gets a reference to the ImageCapture use case
  • Create image store to hold file
  • createOutputFileOptionsSpecify the output mode and output path
valoutputFileOptions = ImageCapture.OutputFileOptions.Builder(File(...) ).build()Copy the code
  • rightimageCaptureThe objecttakePicture()Methods. Pass in what you just builtoutputOptionsAnd a callback to save the image

Final modification code

cameraProviderFuture.addListener(Runnable {
    // 1 Bind the Camera to the lifecycle holder
    val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get(a)// 2 Create Preview.
    val preview = Preview.Builder()
        .build()
        .also {
            / / the preview link previewView
            it.setSurfaceProvider(findViewById<PreviewView>(R.id.viewFinder).getSurfaceProvider())
        }
    / / todo new lines
    // Image capture build
    imageCapture = ImageCapture.Builder()
        .build()
    
    //3 Specifies the camera required
    val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

    try {
        // 4 Unbind before binding
        cameraProvider.unbindAll()
        
        // Todo adds a modified row
        // 5 Bind the user case and camera to the life cycle
        cameraProvider.bindToLifecycle(
            this, cameraSelector, preview, imageCapture)

    } catch(exc: Exception) {
        Log.e(TAG, "Use case binding failed", exc)
    }

}, ContextCompat.getMainExecutor(this))

Copy the code

private fun takePhoto(a) {
        // Get the image capture use case
        valimageCapture = imageCapture ? :return


        // Create a storage file object
        val photoFile = File(
            outputDirectory,
            SimpleDateFormat(FILENAME_FORMAT, Locale.CHINA
            ).format(System.currentTimeMillis()) + ".jpg")

        // Output conditional builds
        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

        // Take an incoming output condition and take a callback
        imageCapture.takePicture(
            outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
                override fun onError(exc: ImageCaptureException) {
                    // Print the exception
                    Log.e(TAG, "Failed to take a photo:${exc.message}", exc)
                }

                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    val savedUri = Uri.fromFile(photoFile)
                    val msg = "Photo taken successfully:$savedUri"
                    Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
                    Log.d(TAG, msg)
                }
            })
    }
Copy the code

Run the show