Google 致力于为黑人社区推动种族平等。查看具体举措

CameraX 架构

CameraX 是对 Jetpack 的补充,可让您更轻松地利用 Camera2 API 的功能。本主题介绍了 CameraX 的架构,包括其结构、如何与 API 搭配使用、如何与生命周期配合使用以及如何组合各种用例。

CameraX 结构

开发者使用 CameraX,借助名为“用例”的抽象概念与设备的相机进行交互。目前提供的用例如下:

  • 预览:接受用于显示预览的 Surface,例如 PreviewView
  • 图片分析:为分析(例如机器学习)提供 CPU 可访问的缓冲区。
  • 图片拍摄:拍摄并保存照片。

不同用例可以组合使用,也可以同时处于活动状态。例如,应用中可以加入预览用例,以便让用户查看进入相机视野的画面;加入图片分析用例,以确定照片里的人物是否在微笑;还可以加入图片拍摄用例,以在人物微笑时拍摄照片。

API 模型

如需使用该库,请指定以下内容:

  • 具有配置选项的所需用例。
  • 通过附加监听器来指定如何处理输出数据。
  • 通过将用例绑定到 Android 架构生命周期来指定目标流程,例如何时启用相机及何时生成数据。

您可以使用 set() 方法配置用例,并使用 build() 方法完成这些用例。每个用例对象都提供一组特定于该用例的 API。例如,图片拍摄用例会提供 takePicture() 方法调用。

应用没有在 onResume()onPause() 中放置具体的启动和停止方法调用,而是使用 cameraProvider.bindToLifecycle() 指定要与相机关联的生命周期。之后,该生命周期会告知 CameraX 何时配置相机拍摄会话并确保相机状态随生命周期的转换相应地变化。

如需了解每个用例的实现步骤,请参阅实现预览分析图片图片拍摄

API 模型示例

预览用例会与 Surface 互动以展示预览。应用使用以下代码创建具有配置选项的用例:

Kotlin

val preview = Preview.Builder().build()
val viewFinder: PreviewView = findViewById(R.id.previewView)

// The use case is bound to an Android Lifecycle with the following code
val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)

// PreviewView creates a surface provider and is the recommended provider
preview.setSurfaceProvider(viewFinder.getSurfaceProvider())

Java

Preview preview = new Preview.Builder().build();
PreviewView viewFinder = findViewById(R.id.view_finder);

// The use case is bound to an Android Lifecycle with the following code
Camera camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview);

// PreviewView creates a surface provider, using a Surface from a different
// kind of view will require you to implement your own surface provider.
preview.previewSurfaceProvider = viewFinder.getSurfaceProvider();

如需查看更多示例代码,请参阅官方 CameraX 示例应用

CameraX 生命周期

CameraX 会按照生命周期确定何时打开相机、何时创建拍摄会话以及何时停止和关闭。用例 API 提供方法调用和回调来监控进度情况。

组合用例中所述,您可以将多个用例一起绑定到单个生命周期。当您的应用需要支持无法组合的用例时,您可以执行以下操作之一:

  • 将兼容的用例划分到多个 Fragment 中,然后在 Fragment 之间进行切换
  • 创建自定义生命周期组件并用其手动控制相机生命周期

如果您将视图用例和相机用例的生命周期所有者分开(例如,如果您使用自定义生命周期或保留 Fragment),则必须通过使用 CameraX.unbindAll() 或分别取消绑定各个用例来确保所有用例均未绑定 CameraX。或者,当您将用例绑定到生命周期时,可以让 CameraX 管理拍摄会话的开启和关闭操作以及用例的取消绑定操作。

如果所有相机功能都对应于单个生命周期感知型组件(例如 AppCompatActivityAppCompat Fragment)的生命周期,那么在绑定全部所需用例时使用该组件的生命周期,可确保相机功能在该组件处于活动状态时准备就绪,并在该组件进入非活动状态时获得安全处置,而不会消耗任何资源。

自定义 LifecycleOwner

对于高级用例,您可以创建自定义 LifecycleOwner,以使您的应用显式控制 CameraX 会话生命周期,而不是将其绑定到标准 Android LifecycleOwner

以下代码示例展示了如何创建简单的自定义 LifecycleOwner:

Kotlin

class CustomLifecycle : LifecycleOwner {
    private val lifecycleRegistry: LifecycleRegistry

    init {
        lifecycleRegistry = LifecycleRegistry(this);
        lifecycleRegistry.markState(Lifecycle.State.CREATED)
    }
    ...
    fun doOnResume() {
        lifecycleRegistry.markState(State.RESUMED)
    }
    ...
    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }
}

Java

public class CustomLifecycle implements LifecycleOwner {
    private LifecycleRegistry lifecycleRegistry;
    public CustomLifecycle() {
        lifecycleRegistry = new LifecycleRegistry(this);
        lifecycleRegistry.markState(Lifecycle.State.CREATED);
    }
   ...
   public void doOnResume() {
        lifecycleRegistry.markState(State.RESUMED);
    }
   ...
    public Lifecycle getLifecycle() {
        return lifecycleRegistry;
    }
}

借助此 LifecycleOwner,您的应用可以将状态转换放置在代码中所需的位置。如需详细了解如何在应用中实现此功能,请参阅实现自定义 LifecycleOwner

并发用例

多个用例可以同时运行。虽然可以将多个用例依序绑定到一个生命周期,但最好通过对 CameraProcessProvider.bindToLifecycle() 的一次调用来绑定所有用例。如需详细了解配置更改的最佳做法,请参阅处理配置更改

在以下代码示例中,应用指定了要创建并同时运行的两个用例,还指定了要同时用于这两个用例的生命周期,以便这两个用例都按照该生命周期启动和停止。

Kotlin

private lateinit var imageCapture: ImageCapture

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

    cameraProviderFuture.addListener(Runnable {
        // Camera provider is now guaranteed to be available
        val cameraProvider = cameraProviderFuture.get()

        // Set up the preview use case to display camera preview.
        val preview = Preview.Builder().build()

        // Set up the capture use case to allow users to take photos.
        imageCapture = ImageCapture.Builder()
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                .build()

        // Choose the camera by requiring a lens facing
        val cameraSelector = CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
                .build()

        // Attach use cases to the camera with the same lifecycle owner
        val camera = cameraProvider.bindToLifecycle(
                this as LifecycleOwner, cameraSelector, preview, imageCapture)

        // Connect the preview use case to the previewView
        preview.setSurfaceProvider(
                previewView.getSurfaceProvider())
    }, ContextCompat.getMainExecutor(this))
}

Java

private ImageCapture imageCapture;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    PreviewView previewView = findViewById(R.id.previewView);

    ListenableFuture cameraProviderFuture =
            ProcessCameraProvider.getInstance(this);

    cameraProviderFuture.addListener(() -> {
        try {
            // Camera provider is now guaranteed to be available
            ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

            // Set up the view finder use case to display camera preview
            Preview preview = new Preview.Builder().build();

            // Set up the capture use case to allow users to take photos
            imageCapture = new ImageCapture.Builder()
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                    .build();

            // Choose the camera by requiring a lens facing
            CameraSelector cameraSelector = new CameraSelector.Builder()
                    .requireLensFacing(lensFacing)
                    .build();

            // Attach use cases to the camera with the same lifecycle owner
            Camera camera = cameraProvider.bindToLifecycle(
                    ((LifecycleOwner) this),
                    cameraSelector,
                    preview,
                    imageCapture);

            // Connect the preview use case to the previewView
            preview.setSurfaceProvider(
                    previewView.getSurfaceProvider());
        } catch (InterruptedException | ExecutionException e) {
            // Currently no exceptions thrown. cameraProviderFuture.get()
            // shouldn't block since the listener is being called, so no need to
            // handle InterruptedException.
        }
    }, ContextCompat.getMainExecutor(this));
}

支持的配置组合如下所示:

预览 分析 图片拍摄 组合用例
为用户提供预览、拍摄照片并分析图片流。
  拍摄照片并分析图片流。
  提供预览,并根据对流式传输图片的分析应用视觉效果。
  显示进入相机视野的画面并根据用户操作拍摄照片。

启用扩展后,只能保证能够使用 ImageCapturePreview。可能无法同时使用 ImageAnalysis,具体取决于 OEM 实现情况。

ImageCapture 不能单独使用,但 PreviewImageAnalysis 可以。

权限

您的应用需要 CAMERA 权限。如需将图片保存到文件中,除非所用设备搭载 Android 10 或更高版本,否则应用还需要 WRITE_EXTERNAL_STORAGE 权限。

如需详细了解如何为应用配置权限,请参阅请求应用权限

要求

CameraX 具有以下最低版本要求:

  • Android API 级别 21
  • Android 架构组件 1.1.1

对于能够感知生命周期的 Activity,请使用 FragmentActivityAppCompatActivity

声明依赖项

要添加 CameraX 的依赖项,您必须将 Google Maven 代码库添加到项目中。

打开项目的 build.gradle 文件并添加 google() 代码库,如下所示:

allprojects {
    repositories {
        google()
        jcenter()
    }
}

将以下内容添加到 Android 代码块的末尾:

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
// For Kotlin projects
kotlinOptions {
    jvmTarget = "1.8"
}

将以下内容添加到应用每个模块的 build.gradle 文件中:

dependencies {
  // CameraX core library using the camera2 implementation
  def camerax_version = "1.0.0-rc02"
  // The following line is optional, as the core library is included indirectly by camera-camera2
  implementation "androidx.camera:camera-core:${camerax_version}"
  implementation "androidx.camera:camera-camera2:${camerax_version}"
  // If you want to additionally use the CameraX Lifecycle library
  implementation "androidx.camera:camera-lifecycle:${camerax_version}"
  // If you want to additionally use the CameraX View class
  implementation "androidx.camera:camera-view:1.0.0-alpha21"
  // If you want to additionally use the CameraX Extensions library
  implementation "androidx.camera:camera-extensions:1.0.0-alpha21"
}

如需详细了解如何配置应用以满足上述要求,请参阅声明依赖项

其他资源

要详细了解 CameraX,请参阅下面列出的其他资源。

Codelab

  • CameraX 使用入门
  • 代码示例

  • 官方 CameraX 示例应用