使用Camera2 API无法启用闪光灯问题求助
嘿,我来帮你排查下相机应用里闪光灯开关失效的问题~从你给出的代码片段来看,这里同时用到了CameraManager(Android 6.0+的手电筒API)和Camera2的CameraDevice API,这种混用很可能是导致功能失效的核心原因之一。下面我一步步帮你梳理问题和解决办法:
闪光灯开关失效的排查与修复方案
1. 先确认权限是否配置到位
闪光灯功能依赖相机权限,先检查AndroidManifest.xml里有没有添加必要配置:
<!-- 核心权限 --> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.FLASHLIGHT" /> <!-- 声明设备特性(可选但建议添加) --> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.flash" android:required="false" />
另外,Android 6.0+必须动态申请相机权限,没有相机权限的话闪光灯根本无法工作。可以在Activity启动时补上权限申请逻辑:
private static final int REQUEST_CAMERA_PERMISSION = 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_flash); // 先检查权限,再初始化闪光灯 if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); } else { initFlashLogic(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CAMERA_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { initFlashLogic(); } else { Toast.makeText(this, "需要相机权限才能使用闪光灯", Toast.LENGTH_SHORT).show(); } } }
2. 统一API使用方式,避免混用
你代码里同时出现了两种相机API,建议根据需求二选一:
方案一:用CameraManager(仅控制闪光灯,简单快捷)
如果你的需求只是开关闪光灯,完全没必要引入复杂的Camera2会话逻辑,用CameraManager足够。调整后的核心代码:
private CameraManager mCameraManager; private String mCameraId; private boolean isTorchOn = false; private Button mTorchOnOffButton; private void initFlashLogic() { mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { // 找到支持闪光灯的相机ID(一般是后置相机) for (String id : mCameraManager.getCameraIdList()) { CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id); Boolean hasFlash = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE); if (hasFlash != null && hasFlash) { mCameraId = id; break; } } } catch (CameraAccessException e) { e.printStackTrace(); } // 绑定按钮点击事件 mTorchOnOffButton.setOnClickListener(v -> toggleTorch()); } private void toggleTorch() { try { if (mCameraManager != null && mCameraId != null) { mCameraManager.setTorchMode(mCameraId, !isTorchOn); isTorchOn = !isTorchOn; // 更新按钮文本反馈状态 mTorchOnOffButton.setText(isTorchOn ? "关闭闪光灯" : "打开闪光灯"); } } catch (CameraAccessException e) { e.printStackTrace(); Toast.makeText(this, "闪光灯操作失败", Toast.LENGTH_SHORT).show(); } }
方案二:用Camera2 API(需要相机预览+闪光灯)
如果你的应用需要同时显示相机预览和控制闪光灯,那就要完整实现Camera2的会话逻辑,绝对不能和CameraManager混用。这里补充你代码里缺失的关键部分:
private CameraDevice cameraDevice; private CameraCaptureSession cameraCaptureSessions; private CaptureRequest.Builder captureRequestBuilder; private boolean isTorchOn = false; private TextureView textureView; // CameraDevice状态回调 private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { cameraDevice = camera; createPreviewSession(); } @Override public void onDisconnected(@NonNull CameraDevice camera) { camera.close(); cameraDevice = null; } @Override public void onError(@NonNull CameraDevice camera, int error) { camera.close(); cameraDevice = null; Toast.makeText(FlashActivity.this, "相机打开失败", Toast.LENGTH_SHORT).show(); } }; // 创建相机预览会话 private void createPreviewSession() { try { SurfaceTexture texture = textureView.getSurfaceTexture(); texture.setDefaultBufferSize(640, 480); Surface surface = new Surface(texture); captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureRequestBuilder.addTarget(surface); cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { cameraCaptureSessions = session; updatePreviewFrame(); } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { Toast.makeText(FlashActivity.this, "预览配置失败", Toast.LENGTH_SHORT).show(); } }, null); } catch (CameraAccessException e) { e.printStackTrace(); } } // 更新预览帧 private void updatePreviewFrame() { if (cameraDevice == null) return; try { captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, null); } catch (CameraAccessException e) { e.printStackTrace(); } } // 切换闪光灯状态 private void toggleFlash() { if (cameraDevice == null || captureRequestBuilder == null) return; try { isTorchOn = !isTorchOn; captureRequestBuilder.set(CaptureRequest.FLASH_MODE, isTorchOn ? CaptureRequest.FLASH_MODE_TORCH : CaptureRequest.FLASH_MODE_OFF); cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, null); mTorchOnOffButton.setText(isTorchOn ? "关闭闪光灯" : "打开闪光灯"); } catch (CameraAccessException e) { e.printStackTrace(); } }
额外提醒:使用Camera2时,要给TextureView绑定监听器,在表面可用时再打开相机:
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { openCamera(); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {} @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { closeCamera(); return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) {} }); // 打开相机 private void openCamera() { CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { String cameraId = getBackCameraId(manager); if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { manager.openCamera(cameraId, stateCallback, null); } } catch (CameraAccessException e) { e.printStackTrace(); } } // 获取后置相机ID private String getBackCameraId(CameraManager manager) throws CameraAccessException { for (String id : manager.getCameraIdList()) { CameraCharacteristics characteristics = manager.getCameraCharacteristics(id); Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) { return id; } } return manager.getCameraIdList()[0]; // 找不到后置就用第一个相机 } // 释放相机资源 private void closeCamera() { if (cameraCaptureSessions != null) { cameraCaptureSessions.close(); cameraCaptureSessions = null; } if (cameraDevice != null) { cameraDevice.close(); cameraDevice = null; } }
3. 额外注意事项
- 提前判断设备是否支持闪光灯(上面的代码已经包含这个逻辑),避免在无闪光灯设备上崩溃
- 当应用退到后台时,记得关闭闪光灯,避免不必要的耗电
- 使用Camera2 API时,一定要处理好资源释放,防止内存泄漏
如果还有具体的报错日志或者代码细节,可以补充出来,我再帮你细化排查~
内容的提问来源于stack exchange,提问作者pandarulez




