You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用同一个onClick按钮实现相机及预览的启动与停止功能

问题原因

你当前代码第二次点击崩溃的核心原因是:每次点击按钮都会重新初始化ProcessCameraProvider,重复向同一个生命周期所有者绑定相机用例,CameraX检测到重复绑定时会直接抛出异常导致崩溃。

实现单按钮启停的修改方案

第一步:新增全局成员变量

在类顶部新增三个变量,分别用于记录相机运行状态、存储相机提供者实例、保存按钮实例:

// 原有变量保留
private boolean isCameraRunning = false;
private ProcessCameraProvider cameraProvider;
private Button captureButton;

第二步:修改点击事件逻辑

修改onCreate中的按钮绑定和点击逻辑,增加状态判断:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    previewView = findViewById(R.id.previewView);
    captureButton = findViewById(R.id.buttonPreview);
    captureButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
          if (allPermissionsGranted()) {
              // 根据相机运行状态判断调用启动还是停止逻辑
              if (isCameraRunning) {
                  stopCamera();
              } else {
                  startCamera();
              }
          } else {
              ActivityCompat.requestPermissions(MainActivity.this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
          }
      }
    });
}

第三步:改造startCamera方法

修改原有启动方法,将cameraProvider存为全局变量,绑定成功后更新状态和按钮文字:

public void startCamera() {
    ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);
    cameraProviderFuture.addListener(() -> {
        try {
            // 存储到全局变量,不要每次重新获取
            cameraProvider = cameraProviderFuture.get();
            Preview preview = new Preview.Builder().build();
            CameraSelector cameraSelector = new CameraSelector.Builder()
                    .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                    .build();
            ImageAnalysis imageAnalysis =
                    new ImageAnalysis.Builder()
                            .setTargetResolution(new Size(1280, 720))
                            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                            .build();
            preview.setSurfaceProvider(previewView.getSurfaceProvider());
            // 绑定前先解绑所有已存在的用例,避免残留
            cameraProvider.unbindAll();
            cameraProvider.bindToLifecycle(
                    ((LifecycleOwner) this),
                    cameraSelector,
                    preview,
                    imageAnalysis);
            // 更新状态和按钮文字
            isCameraRunning = true;
            captureButton.setText("停止预览");
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }, ContextCompat.getMainExecutor(this));
}

第四步:新增stopCamera停止方法

新增停止逻辑,释放所有相机用例并重置状态:

private void stopCamera() {
    if (cameraProvider != null) {
        // 解绑所有用例,相机会自动关闭
        cameraProvider.unbindAll();
    }
    isCameraRunning = false;
    captureButton.setText("启动预览");
}

运行逻辑说明

  • 首次点击按钮:权限校验通过后启动相机,按钮文字变为「停止预览」
  • 再次点击按钮:释放所有相机用例,预览自动关闭,按钮文字恢复为「启动预览」
  • 重复点击会循环执行上述逻辑,不会出现崩溃问题

内容的提问来源于stack exchange,提问作者Curious_student

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 12:15:04