Android相机系列之快速使用 CameraX 实现实时预览

734 阅读4分钟

0 引言

CameraX 是一个 Jetpack 库,旨在帮助开发者更轻松地开发相机应用。它提供了一个一致且易于使用的 API,该 API 适用于绝大多数 Android 设备,并向后兼容 Android 5.0(API 级别 21)。

与之对应的是Camera2,它是低级别 Android 相机软件包,用于替代已废弃的 Camera 类。Camera2 可为复杂的用例提供深入的控制功能,但要求您管理设备专属配置。

CameraX 从几个主要方面改善了开发者体验。

  1. 广泛的设备兼容性:CameraX 支持搭载 Android 5.0(API 级别 21)或更高版本的设备,覆盖现有 Android 设备的 98% 以上。
  2. 易用性:CameraX 着重于用例,使开发者可以专注于需要完成的任务,而无需花时间处理不同设备之间的细微差别。CameraX 支持大多数常见的相机用例:预览、图片分析、图片拍摄和视频拍摄。
  3. 确保各设备间的一致性:要维持一致的相机行为并非易事。开发者必须考虑宽高比、屏幕方向、旋转角度、预览大小和图像大小。有了 CameraX,这些基本行为都不用再费心。

1 创建项目与依赖配置

首先创建一个Empty Views Activity项目:

image.png

开发语言这里选择Java,构建配置语言选择Groovy:

image.png

接着app模块的build.gradle文件中添加Gradle依赖项:

dependencies {
    def camerax_version = "1.3.0-alpha04"
    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-video:$camerax_version"
    implementation "androidx.camera:camera-view:$camerax_version"
    implementation "androidx.camera:camera-extensions:$camerax_version"
}

应用需要获得用户授权才能打开相机,因此打开 AndroidManifest.xml,然后将以下代码行添加到 application 标记之前:

<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.CAMERA" />

最后修改布局文件activity_main.xml,加入相机预览视图androidx.camera.view.PreviewView:

<androidx.camera.view.PreviewView
    android:id="@+id/previewView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

让PreviewView占满整个布局界面。这样整个项目的整体框架就搭建好了,接下来就是代码层面的内容了。

2 声明成员变量

在一个使用CameraX实现的简单的相机实时预览项目中,主要需要定义三个重要的成员变量:ListenableFuture、PreviewView和CameraSelector。代码如下:

    private ListenableFuture<ProcessCameraProvider> processCameraProviderListenableFuture;
    private PreviewView previewView;
    private CameraSelector cameraSelector;

ProcessCameraProviderCameraX 的核心类,用于绑定和管理相机的生命周期。
ListenableFuture 是一个异步任务的接口,用于获取 ProcessCameraProvider 的实例。
它是 Guava 库 中的类,支持回调机制,可以监听任务完成的状态。

PreviewView 是 CameraX 提供的 UI 组件,用于显示相机的实时预览。它继承自 FrameLayout,可以方便地添加到布局中,支持调整显示方式(如裁剪、拉伸)。

CameraSelector 用于选择相机的前后摄像头(或其他特定摄像头)。它是 CameraX 提供的一个工具类,提供了便捷的选择器。

2 请求相机权限

在程序中,我们要先判断App是否有相机权限,如果有则开始打开相机。

// App拥有所需权限才打开相机,否则请求相机权限
if (allPermissionsGranted()) {
    startCamera();
} else {
    ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
}

// 遍历所需权限数组REQUIRED_PERMISSIONS
private boolean allPermissionsGranted() {
    for (String permission : REQUIRED_PERMISSIONS) {
        if (ContextCompat.checkSelfPermission(this, permission)
                != PackageManager.PERMISSION_GRANTED) {
            return false;
        }
    }
    return true  
}

// 监听权限请求结果,权限获取到后继续调用startCamera()函数
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_CODE_PERMISSIONS) {
        if (allPermissionsGranted()) {
            startCamera();
        }
    }
}

3 通过 CameraX 实现相机预览绑定

启动CameraX

private void startCamera() {
    // 获取 ProcessCameraProvider 的异步实例
    processCameraProviderListenableFuture = ProcessCameraProvider.getInstance(this);
    // 通过 `ListenableFuture` 的监听器在实例可用时执行绑定相机操作
    processCameraProviderListenableFuture.addListener(() -> {
        try {
            ProcessCameraProvider processCameraProvider = processCameraProviderListenableFuture.get();
            bindCamera(processCameraProvider);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }, ContextCompat.getMainExecutor(this));
}

绑定相机到生命周期

private void bindCamera(ProcessCameraProvider processCameraProvider) {
    // 调用 `unbindAll()` 释放之前绑定的所有相机资源,确保不会出现重复绑定
    processCameraProvider.unbindAll();
    // 使用 `CameraSelector` 指定相机镜头
    cameraSelector = new CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build();
    // 配置 `Preview` 并将其与 `PreviewView` 的 `SurfaceProvider` 绑定
    Preview preview = new Preview.Builder().build();
    preview.setSurfaceProvider(previewView.getSurfaceProvider());
    // 通过 `bindToLifecycle()` 方法,将相机绑定到当前 Activity 的生命周期
    processCameraProvider.bindToLifecycle(this, cameraSelector, preview);
}

4 结果与总结

GIF 2024-12-29 22-56-21.gif

通过本篇博客,我们详细讲解了如何快速使用 CameraX 实现相机实时预览的完整流程。从项目初始化、权限配置到相机启动与绑定,每一步都展示了清晰的代码示例与实现思路,帮助开发者快速上手 CameraX 的核心功能。