如何借助Mobile Vision API实现手电筒的开启与关闭?
解决Mobile Vision API中CameraSource与CameraManager手电筒冲突问题
问题描述
使用Mobile Vision API实现文字识别时,尝试通过CameraManager控制手电筒,虽能成功开启,但调用setTorchMode(mCameraId, false)无法关闭,推测是CameraSource与CameraManager同时抢占相机资源导致冲突。
可行解决办法
方案1:反射操作CameraSource内部相机实例
CameraSource未公开闪光灯控制API,可通过反射获取其内部相机对象(兼容旧版Camera和新版camera2 API),直接操作闪光灯模式,避免与CameraManager的资源冲突。
步骤1:补充权限与状态变量
在AndroidManifest.xml中添加闪光灯权限:
<uses-permission android:name="android.permission.FLASHLIGHT" /> <uses-feature android:name="android.hardware.camera.flash" android:required="false" />
在MainActivity中添加状态标记:
private boolean isFlashOn = false;
步骤2:实现手电筒切换方法
private void toggleFlash() { try { // 尝试反射获取旧版Camera实例 Field cameraField = CameraSource.class.getDeclaredField("mCamera"); cameraField.setAccessible(true); Camera mCamera = (Camera) cameraField.get(cameraSource); if (mCamera != null) { Camera.Parameters params = mCamera.getParameters(); if (isFlashOn) { params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); isFlashOn = false; } else { params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); isFlashOn = true; } mCamera.setParameters(params); return; } } catch (NoSuchFieldException | IllegalAccessException e) { // 旧版API反射失败,尝试camera2 API try { Field cameraDeviceField = CameraSource.class.getDeclaredField("mCameraDevice"); cameraDeviceField.setAccessible(true); CameraDevice cameraDevice = (CameraDevice) cameraDeviceField.get(cameraSource); if (cameraDevice != null) { CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); if (isFlashOn) { builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); isFlashOn = false; } else { builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); isFlashOn = true; } cameraDevice.setRepeatingRequest(builder.build(), null, null); } } catch (Exception ex) { ex.printStackTrace(); } } }
步骤3:添加触发按钮
修改activity_main.xml,增加切换按钮:
<RelativeLayout ...> <!-- 原有SurfaceView和TextView --> <Button android:id="@+id/flash_toggle_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentEnd="true" android:text="切换手电筒" /> </RelativeLayout>
在MainActivity的onCreate中绑定点击事件:
Button flashBtn = findViewById(R.id.flash_toggle_btn); flashBtn.setOnClickListener(v -> toggleFlash());
方案2:自定义CameraSource(更稳定)
Google的CameraSource为开源代码,可将其源码复制到项目中,直接添加控制闪光灯的公开方法,避免反射的兼容性问题。核心逻辑是在自定义CameraSource中新增setFlashMode方法,直接操作内部相机实例切换闪光灯状态。
原理说明
CameraSource启动后会独占相机资源,此时CameraManager无法正常修改该相机的手电筒状态。通过反射或自定义CameraSource操作同一相机实例,能确保闪光灯控制命令直接作用于当前正在使用的相机,避免资源冲突。
内容的提问来源于stack exchange,提问作者Clint William Theron
相关产品推荐
相关产品推荐

