Android SurfaceView相机打开即闪退、加载慢及相机启动最佳实践咨询
问题解决方法
1. 相机预览立即消失的修复
你遇到的预览消失问题和surfaceDestroyed里的cameraSource.stop()无关,这行是符合生命周期逻辑的正常代码。核心原因是OCR检测器的receiveDetections回调会实时返回识别结果,只要检测到任意文字就会触发resultObtained()方法,方法内执行setContentView(R.layout.activity_main)直接替换了包含SurfaceView的相机预览布局,Surface被销毁后自然会触发停止相机的逻辑,导致预览一闪而过。
修复方案可以二选一:
- 新增手动识别按钮,删除
receiveDetections里自动调用resultObtained()的逻辑,用户点击按钮后再提取识别结果、跳转布局,避免刚打开相机就因为识别到模糊内容自动切页。示例修改代码如下:
// 新增全局按钮变量 private Button captureBtn; private void textRecognizer(){ // 原有初始化逻辑保留 textRecognizer = new TextRecognizer.Builder(getApplicationContext()).build(); cameraSource = new CameraSource.Builder(getApplicationContext(), textRecognizer) .setRequestedPreviewSize(1280, 1024) .build(); surfaceView = findViewById(R.id.surfaceView); // 新增按钮初始化 captureBtn = findViewById(R.id.capture_btn); captureBtn.setOnClickListener(v -> { if (stringResult != null) { resultObtained(); } }); // 原有Surface回调逻辑保留 surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() { @SuppressLint("MissingPermission") @Override public void surfaceCreated(SurfaceHolder holder) { try { cameraSource.start(surfaceView.getHolder()); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { cameraSource.stop(); } }); textRecognizer.setProcessor(new Detector.Processor<TextBlock>() { @Override public void release() { } @Override public void receiveDetections(Detector.Detections<TextBlock> detections) { SparseArray<TextBlock> sparseArray = detections.getDetectedItems(); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i<sparseArray.size(); ++i){ TextBlock textBlock = sparseArray.valueAt(i); if (textBlock != null && textBlock.getValue() !=null){ stringBuilder.append(textBlock.getValue() + " "); } } stringResult = stringBuilder.toString(); // 删掉原来自动调用resultObtained的逻辑 } }); }
- 如果要保留自动识别逻辑,增加识别校验阈值,比如连续3次回调都返回相同文本、或者文本长度满足要求后再触发切页,避免误触发。
2. 相机启动慢优化&最佳实践
现有代码的问题修复
你当前的权限申请代码写法错误,ActivityCompat.requestPermissions的第三个参数是自定义的请求码,你传了PackageManager.PERMISSION_GRANTED会导致权限申请回调异常,这是相机启动慢的核心原因之一,修改为自定义请求码即可:
// 自定义权限请求码 private static final int PERMISSION_REQUEST_CAMERA = 0x101; // onCreate里的权限申请修改为 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA);
同时要重写onRequestPermissionsResult方法,监听权限申请结果,权限通过后再初始化相机相关组件,不要等到点击按钮才初始化。
通用优化方案
- 不要反复调用
setContentView切换布局,每次调用都会重新渲染整个视图树,开销极大。建议将主布局和相机预览布局放在同一个XML文件中,通过View.setVisibility()控制两者的显示隐藏。 - 不要硬编码预览尺寸,先获取当前设备支持的相机预览分辨率,选择和SurfaceView尺寸最接近的分辨率设置,避免适配开销。
- 优化生命周期管理:将相机启动逻辑放到
onResume中,停止逻辑放到onPause中,减少后台资源占用。 - 条件允许的情况下,替换老旧的CameraSource为Google官方的CameraX库,CameraX做了大量设备兼容性适配,启动速度更快、适配成本更低,是当前Android相机开发的首选方案。
内容的提问来源于stack exchange,提问作者user17463763
相关产品推荐
相关产品推荐

