如何使用同一个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
相关产品推荐
相关产品推荐

