Android CameraX 使用指南:简化相机开发

前言

在Android开发中,相机功能一直是比较复杂的部分,需要处理不同设备的兼容性、生命周期管理以及复杂的API调用。Google推出的CameraX库极大地简化了这一过程,让开发者能够更轻松地实现高质量的相机功能。本文将带你全面了解CameraX的使用方法。

什么是CameraX?

CameraX是Jetpack系列中的一个库,它基于Camera2 API构建,但提供了更高层次的抽象,具有以下优点:

  • 简化API:比Camera2 API更易于使用

  • 生命周期感知:自动管理相机生命周期

  • 设备兼容性:处理不同厂商设备的兼容性问题

  • 一致的行为:在不同设备上提供更一致的体验

添加依赖

首先,在build.gradle文件中添加CameraX依赖:

复制代码
def camerax_version = "1.3.0"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
implementation "androidx.camera:camera-view:${camerax_version}"

基本使用流程

1. 请求相机权限

在AndroidManifest.xml中添加权限声明:

复制代码
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />

运行时请求权限:

复制代码
private val requestPermissionLauncher = registerForActivityResult(
    ActivityResultContracts.RequestPermission()
) { isGranted ->
    if (isGranted) {
        startCamera()
    } else {
        Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
    }
}

// 检查并请求权限
if (ContextCompat.checkSelfPermission(
        this, Manifest.permission.CAMERA
    ) == PackageManager.PERMISSION_GRANTED
) {
    startCamera()
} else {
    requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}

2. 配置预览视图

在布局文件中添加PreviewView:

复制代码
<androidx.camera.view.PreviewView
    android:id="@+id/viewFinder"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

3. 初始化CameraX

复制代码
private fun startCamera() {
    val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

    cameraProviderFuture.addListener({
        // 用于绑定相机生命周期
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

        // 预览
        val preview = Preview.Builder()
            .build()
            .also {
                it.setSurfaceProvider(viewFinder.surfaceProvider)
            }

        // 选择后置摄像头
        val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

        try {
            // 解绑之前的所有用例
            cameraProvider.unbindAll()

            // 绑定用例到生命周期
            cameraProvider.bindToLifecycle(
                this, cameraSelector, preview
            )
        } catch(exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }
    }, ContextCompat.getMainExecutor(this))
}

高级功能

图像分析

CameraX可以轻松实现图像分析:

复制代码
val imageAnalysis = ImageAnalysis.Builder()
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .build()

imageAnalysis.setAnalyzer(executor) { imageProxy ->
    // 在这里处理图像
    val rotationDegrees = imageProxy.imageInfo.rotationDegrees
    // 处理完成后关闭imageProxy
    imageProxy.close()
}

// 记得在bindToLifecycle中添加这个用例
cameraProvider.bindToLifecycle(
    this, cameraSelector, preview, imageAnalysis
)

拍照功能

复制代码
private fun takePhoto() {
    // 创建图片捕获用例
    val imageCapture = ImageCapture.Builder()
        .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
        .build()

    // 绑定用例
    cameraProvider.bindToLifecycle(
        this, cameraSelector, preview, imageCapture
    )

    // 创建输出选项
    val outputOptions = ImageCapture.OutputFileOptions.Builder(
        File(externalMediaDirs.first(), "${System.currentTimeMillis()}.jpg")
    ).build()

    // 拍照
    imageCapture.takePicture(
        outputOptions,
        ContextCompat.getMainExecutor(this),
        object : ImageCapture.OnImageSavedCallback {
            override fun onError(exc: ImageCaptureException) {
                Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
            }

            override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                val savedUri = output.savedUri ?: Uri.fromFile(outputOptions.outputFile)
                Log.d(TAG, "Photo capture succeeded: $savedUri")
            }
        }
    )
}

处理设备特性

CameraX提供了简单的方式来检查设备支持的功能:

复制代码
val cameraInfo = cameraProvider.availableCameraInfos.find {
    it.cameraSelector == cameraSelector
}

// 检查闪光灯支持
val hasFlash = cameraInfo?.torchState?.value != null

// 检查变焦支持
val hasZoom = cameraInfo?.zoomState?.value != null

最佳实践

  1. 生命周期管理:确保正确绑定到生命周期所有者

  2. 错误处理:妥善处理所有可能的异常

  3. 资源清理:及时关闭ImageProxy等资源

  4. 线程管理:使用合适的Executor

  5. 性能优化:根据需求选择合适的配置(分辨率、帧率等)

总结

CameraX极大地简化了Android相机开发,让开发者能够专注于业务逻辑而不是底层细节。通过本文的介绍,你应该已经掌握了CameraX的基本用法和一些高级功能。现在,你可以尝试在自己的应用中实现相机功能了!

参考资源

希望这篇博客对你有所帮助!如果有任何问题,欢迎在评论区讨论。

相关推荐
驱动开发0079 分钟前
UVC相机注入视频文件,让你的物理相机显示成视频的内容
数码相机
帅次43 分钟前
Android 高级工程师面试参考答案:架构设计、Jetpack 与 Compose
android·面试·职场和发展·架构·composer·jetpack
limingade1 小时前
Dialer3.0智能拨号器Android版功能说明书
android·蓝牙电话·手机转sip·手机蓝牙·智能拨号器
JJay.1 小时前
Android BLE 的 notify 和 indicate 到底有什么区别
android
橙子199110161 小时前
Android 异步任务和消息机制
android
被开发耽误的大厨1 小时前
5、Integer缓存池里同一个对象指的是什么?Integer 和String 内存结构逻辑完全一样?
android·java·哈希算法
NoSi EFUL9 小时前
MySQL中ON DUPLICATE KEY UPDATE的介绍与使用、批量更新、存在即更新不存在则插入
android·数据库·mysql
安小牛12 小时前
Android 开发汉字转带声调的拼音
android·java·学习·android studio
聚美智数12 小时前
企业实际控制人查询-公司实控人查询
android·java·javascript
JMchen12313 小时前
第 3 篇|Android 项目结构解析与第一个界面 —— Hello, CSDN!
android·android studio·android 零基础·android 项目结构·android 界面开发