“This is the second day of my participation in the Gwen Challenge in November. See details: The Last Gwen Challenge in 2021”

CameraX is a Jetpack support library that leverages camera2’s lifecycle awareness, resolves device compatibility issues, and provides backward compatibility to Android 5.0 (API level 21) with a consistent and easy-to-use API interface. With CameraX, developers can achieve the same camera experience and functionality as pre-installed camera apps with just two lines of code!

It’s an architecture, and officially it’s very powerful and easy to use, so try it out.

1. Create exercises for CameraX

MinSdkVersion 21, Android 5.0.

2. Add dependencies

CameraX Core Library Using camerA2 implementation "Androidx. Camera: Camera2:1.0.1 CameraX View class implementation Lifecycle Library implementation "Androidx. camera: CameraX: Lifecycle :1.0.1 "Androidx. Camera: the camera - view: 1.0.0 - alpha27"Copy the code

3. Add the kotlin-Android-extensions extension

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}
Copy the code

4. Write the layout file activity_main.xml

<? The XML version = "1.0" encoding = "utf-8"? > <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/camera_capture_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="30dp" android:elevation="2dp" android:scaleType="fitCenter" android:text="Take Photo" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> <androidx.camera.view.PreviewView android:id="@+id/viewFinder" android:layout_width="match_parent" android:layout_height="match_parent" /> </androidx.constraintlayout.widget.ConstraintLayout>Copy the code

5. Open androidmanifest.xml to add permissions

<! - to ensure that the equipment has a camera. Any means may be front-facing camera or rear camera - > < USES - feature android: name = "android. Hardware. Camera. Any" / > <uses-permission android:name="android.permission.CAMERA" />Copy the code

6, formal writing code, including open the camera, capture images, save pictures, picture analysis and so on.

Steps:

  • Add the CameraX dependency to the project.
  • Show the camera viewfinder (using the preview use case).
  • Implement photo capture and save the image to storage (using the ImageCapture use case).
  • Analyze frames from the camera in real time (using the ImageAnalysis use case).
package com.pyn.cameraxpractice import android.Manifest import android.content.pm.PackageManager import android.net.Uri import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.util.Log import android.widget.Toast import androidx.camera.core.* import androidx.camera.lifecycle.ProcessCameraProvider import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import com.pyn.cameraxpractice.databinding.ActivityMainBinding import java.io.File import java.nio.ByteBuffer import java.text.SimpleDateFormat import java.util.* import java.util.concurrent.ExecutorService import java.util.concurrent.Executors class MainActivity : AppCompatActivity() { private lateinit var mBinding: ActivityMainBinding private var imageCapture: ImageCapture? = null private lateinit var outputDirectory: File private lateinit var cameraExecutor: ExecutorService override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBinding = ActivityMainBinding.inflate(layoutInflater) SetContentView (mbinding.root) if (allPermissionsGranted()) { And authorized startCamera ()} else {ActivityCompat. RequestPermissions (this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS) } mBinding.btnCameraCapture.setOnClickListener { takePhoto() } outputDirectory = GetOutputDirectory () cameraExecutor = Executors. NewSingleThreadExecutor ()} / * * * request permissions callback * / override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<String>, grantResults: IntArray) {if (requestCode == REQUEST_CODE_PERMISSIONS) {if (allPermissionsGranted()) {  } else { Toast.makeText( this, "Permissions not granted by the user.", Toast.length_short).show() finish()}}} /** * take photos */ private fun takePhoto() {// Get a reference to the ImageCapture use case val ImageCapture = imageCapture?: return // create a file to save the image. Add a timestamp so that the file name is unique. val photoFile = File( outputDirectory, SimpleDateFormat(FILENAME_FORMAT, Locale.us).format(system.currentTimemillis ()) + ".jpg") // specify to save the output in the file we just created val outputOptions = ImageCapture. OutputFileOptions. Builder (photoFile). The build () / / photo ImageCapture takePicture (outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback { override fun onError(exception: ImageCaptureException) { Log.e(TAG, "Photo capture failed: ${exception.message}", exception) } override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { val savedUri = Uri.fromFile(photoFile) val msg = "Photo capture succeeded: $savedUri" Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show() Log.d(TAG, MSG)}})} /** * Open camera */ private Fun startCamera() { Because CameraX has lifecycle awareness. Val cameraProviderFuture = ProcessCameraProvider. GetInstance (this) / / add a listener to cameraProviderFuture. / / parameters: Runnable / / parameter 2: ContextCompat. GetMainExecutor () will return a run on the main thread of the Executor. CameraProviderFuture. AddListener (Runnable {/ / is used to the life cycle of the camera is bound to in the process of the application of LifecycleOwner val cameraProvider: ProcessCameraProvider = cameraproviderFuture.get () // Initializes the preview object, the viewfinder is used to let the user preview the photo, Val Preview = preview.builder ().build().also { it.setSurfaceProvider(mBinding.viewFinder.surfaceProvider) } imageCapture = ImageCapture.Builder().build() val imageAnalyzer = ImageAnalysis.Builder() .build() .also { it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma -> Log.d(TAG, "Average luminosity: $luma")})} val cameraSelector = camerasElector.default_back_camera try {// Unbind the use case before rebinding CameraProvider. UnbindAll () / / cameraSelector and preview object binding to cameraProvider cameraProvider. BindToLifecycle (this, cameraSelector, preview, imageCapture, imageAnalyzer) } catch (exc: Exception) {// binding failed log. e(TAG, "Use case binding failed", exc)}}, ContextCompat.getMainExecutor(this)) } private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all { ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED } private fun getOutputDirectory(): File { val mediaDir = externalMediaDirs.firstOrNull()? .let { File(it, resources.getString(R.string.app_name)).apply { mkdirs() } } return if (mediaDir ! = null && mediaDir.exists()) mediaDir else filesDir } override fun onDestroy() { super.onDestroy() cameraExecutor.shutdown() } companion object { private const val TAG = "CameraXBasic" private const val FILENAME_FORMAT = "yyyy-MM-dd-HH" private const val REQUEST_CODE_PERMISSIONS = 10 private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA) } private class LuminosityAnalyzer(private val listener: LumaListener) : ImageAnalysis.Analyzer { private fun ByteBuffer.toByteArray(): ByteArray {// Rewind rewind() val data = ByteArray(remaining()) get(data) return data} Override fun analyze(image: ImageProxy) { val buffer = image.planes[0].buffer val data = buffer.toByteArray() val pixels = data.map { it.toInt() and  0xFF } val luma = pixels.average() listener(luma) image.close() } } } typealias LumaListener = (luma: Double) -> UnitCopy the code

After saving the picture, you can find the picture from the phone file. The address is as follows:

Analysis logs are as follows:


The above is just a simple exercise according to the official documents. For more details, I still need to look at the official documents for more research. The API is very flexible. Try more.


The attached:

CameraX developer community “BBS” : groups.google.com/a/android.c…

CameraX API best Practices: github.com/android/cam…

The official introduction to address: developer.android.com/training/ca…


🌈 follow me ac~ ❤️

Public account: Ni K Ni K