Android CameraX 相机库

FreeGuideOnline 最新 2026-07-13

kotlin dependencies { val camerax_version = "1.4.1" // 核心 CameraX 库 implementation("androidx.camera:camera-core:${camerax_version}") // CameraX 生命周期感知组件 implementation("androidx.camera:camera-lifecycle:${camerax_version}") // 用于显示预览的 View implementation("androidx.camera:camera-view:${camerax_version}") // 可选:如果你想使用 Camera2 的互操作功能 implementation("androidx.camera:camera-camera2:${camerax_version}") }


> **注意**:务必使用相同版本的 CameraX 依赖,避免版本冲突。

---

## 权限处理

在 `AndroidManifest.xml` 中声明相机权限:

```xml
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-permission android:name="android.permission.CAMERA" />

如果是拍照并保存到外部存储,还需要存储写入权限(Android 10 以下):

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28" />

在 Activity 中动态请求权限:

private val requestPermissionLauncher =
    registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
        if (isGranted) {
            startCamera()
        } else {
            // 处理权限被拒情况
        }
    }

private fun checkCameraPermission() {
    when {
        ContextCompat.checkSelfPermission(
            this, Manifest.permission.CAMERA
        ) == PackageManager.PERMISSION_GRANTED -> startCamera()
        else -> requestPermissionLauncher.launch(Manifest.permission.CAMERA)
    }
}

核心用例详解

CameraX 将相机操作抽象为三个基本用例,你可以根据需要组合使用。

1. Preview(预览)

将取景流显示在界面上。使用 PreviewView 来承载画面。

<!-- layout/activity_main.xml -->
<androidx.camera.view.PreviewView
    android:id="@+id/viewFinder"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
val preview = Preview.Builder()
    .build()
    .also {
        it.setSurfaceProvider(viewFinder.surfaceProvider)
    }

2. ImageCapture(拍照)

拍摄照片并保存到文件或获取 Bitmap。在绑定用例时构建。

val imageCapture = ImageCapture.Builder()
    .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) // 或 MAXIMIZE_QUALITY
    .build()

// 拍照并保存到文件
fun takePhoto() {
    val imageFile = File(externalMediaDirs.first(), "${System.currentTimeMillis()}.jpg")
    val outputOptions = ImageCapture.OutputFileOptions.Builder(imageFile).build()
    imageCapture.takePicture(
        outputOptions,
        ContextCompat.getMainExecutor(this),
        object : ImageCapture.OnImageSavedCallback {
            override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                // 照片已保存到 imageFile
            }
            override fun onError(exception: ImageCaptureException) {
                // 处理错误
            }
        }
    )
}

3. ImageAnalysis(帧分析)

对相机帧进行实时处理,如二维码扫描、图像识别等。

val imageAnalysis = ImageAnalysis.Builder()
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .build()

imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this)) { imageProxy ->
    // 在这里处理每一帧,比如传入 ML Kit
    val mediaImage = imageProxy.image
    if (mediaImage != null) {
        // 使用 mediaImage 进行分析
    }
    // 用完记得关闭
    imageProxy.close()
}

绑定生命周期并启动相机

ProcessCameraProvider 将用例绑定到当前生命周期的拥有者。

private fun startCamera() {
    val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
    cameraProviderFuture.addListener({
        val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

        // 选择后置摄像头作为默认
        val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

        try {
            // 解绑所有用例再重新绑定
            cameraProvider.unbindAll()
            cameraProvider.bindToLifecycle(
                this,          // LifecycleOwner
                cameraSelector,
                preview,
                imageCapture,
                imageAnalysis
            )
        } catch (e: Exception) {
            // 处理异常
        }
    }, ContextCompat.getMainExecutor(this))
}

绑定成功后,预览就会自动显示在 PreviewView 中。


高级配置

选择镜头与摄像头

通过 CameraSelector 可以精确选择:

val cameraSelector = CameraSelector.Builder()
    .requireLensFacing(CameraSelector.LENS_FACING_FRONT) // 前置摄像头
    .build()

如果设备没有对应镜头,CameraX 会自动降级到可用的镜头。

分辨率策略

设置目标分辨率和宽高比:

val preview = Preview.Builder()
    .setTargetAspectRatio(AspectRatio.RATIO_16_9)
    .setTargetResolution(android.util.Size(1920, 1080))
    .build()

对于 ImageCapture,可以设置目标分辨率,但最终由设备实际支持的分辨率决定,CameraX 会选择最接近的。

启用闪光灯、旋转等

// 在 Preview 或 ImageCapture 中设置
val camera = cameraProvider.bindToLifecycle(...)

// 控制闪光灯
camera.cameraControl.enableTorch(true) // 打开手电筒

// 手动设置曝光补偿等(需要 Camera2 互操作)

与其他库集成

  • 二维码扫描:结合 ML Kit Barcode Scanning,在 ImageAnalysis 中处理。
  • Camera2 互操作:通过 Camera2Interop.Extender 访问底层 Camera2 特性。

完整示例代码片段

下面是一个在 Fragment 中使用 CameraX 的最小化完整示例(省略了布局文件,仅展示 Kotlin 代码):

class CameraFragment : Fragment() {
    private lateinit var viewFinder: PreviewView
    private lateinit var imageCapture: ImageCapture

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return inflater.inflate(R.layout.fragment_camera, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewFinder = view.findViewById(R.id.viewFinder)
        checkCameraPermission()
    }

    private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
        cameraProviderFuture.addListener({
            val cameraProvider = cameraProviderFuture.get()
            val preview = Preview.Builder().build().also {
                it.setSurfaceProvider(viewFinder.surfaceProvider)
            }
            imageCapture = ImageCapture.Builder().build()
            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

            try {
                cameraProvider.unbindAll()
                cameraProvider.bindToLifecycle(
                    viewLifecycleOwner, cameraSelector, preview, imageCapture
                )
            } catch (e: Exception) {
                Log.e("CameraX", "绑定失败", e)
            }
        }, ContextCompat.getMainExecutor(requireContext()))
    }

    private fun takePhoto() {
        val photoFile = File(requireContext().externalMediaDirs.first(), "photo.jpg")
        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
        imageCapture.takePicture(
            outputOptions, ContextCompat.getMainExecutor(requireContext()),
            object : ImageCapture.OnImageSavedCallback {
                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    Toast.makeText(requireContext(), "照片已保存", Toast.LENGTH_SHORT).show()
                }
                override fun onError(exception: ImageCaptureException) {
                    Toast.makeText(requireContext(), "拍照失败", Toast.LENGTH_SHORT).show()
                }
            }
        )
    }

    // 省略 checkCameraPermission 方法,见上文
}