Android Camera API调用startPreview失败运行时异常求助
解决Android Camera API多次拍摄后startPreview失败的问题
这种多次拍摄后触发startPreview failed的RuntimeException我之前做相机应用时也踩过坑,大概率是相机状态混乱或者资源没处理到位导致的,咱们一步步来排查解决:
核心问题分析
你当前的逻辑是拍完照直接在onPictureTaken里调用startPreview(),但相机刚完成拍照操作,内部状态还没完全回到可预览的就绪状态,多次重复这个操作后就容易出现状态冲突,引发崩溃。
具体解决方案
1. 给相机状态恢复留缓冲时间,先停再启预览
在onPictureTaken回调里,先停止当前预览,处理完照片数据后延迟一小段时间再重启预览,给相机足够的状态重置时间:
@Override public void onPictureTaken(final byte[] data, Camera camera) { // 先停止当前预览,避免状态冲突 camera.stopPreview(); // 这里处理照片数据(比如写入文件、压缩等) savePictureData(data); // 延迟100-300ms再启动预览,时间可根据设备调整 new Handler(Looper.getMainLooper()).postDelayed(() -> { try { camera.startPreview(); } catch (RuntimeException e) { // 捕获异常,触发相机重置逻辑 resetCamera(); } }, 200); }
2. 确保相机资源被正确释放,避免泄漏
多次拍摄后如果资源没妥善回收,会导致相机服务异常。一定要在Activity的生命周期方法里释放相机:
@Override protected void onPause() { super.onPause(); releaseCamera(); } @Override protected void onDestroy() { super.onDestroy(); releaseCamera(); } private void releaseCamera() { if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } }
同时,当startPreview失败时,要做相机重置逻辑,彻底释放后重新初始化:
private void resetCamera() { releaseCamera(); // 重新初始化相机 initCamera(); } private void initCamera() { try { mCamera = Camera.open(); // 配置相机参数(预览尺寸、拍照尺寸等) setupCameraParams(); mCamera.setPreviewDisplay(mSurfaceHolder); mCamera.startPreview(); } catch (IOException | RuntimeException e) { e.printStackTrace(); } }
3. 避免相机参数冲突,确保参数配置正确
多次拍摄后可能出现参数被意外修改的情况,每次启动预览前重新确认相机参数:
private void setupCameraParams() { if (mCamera == null) return; Camera.Parameters params = mCamera.getParameters(); // 选择适配SurfaceView的最优预览尺寸 List<Camera.Size> previewSizes = params.getSupportedPreviewSizes(); Camera.Size optimalPreviewSize = getOptimalSize(previewSizes, mSurfaceView.getWidth(), mSurfaceView.getHeight()); params.setPreviewSize(optimalPreviewSize.width, optimalPreviewSize.height); // 配置拍照尺寸(建议和预览尺寸比例一致,避免拉伸) List<Camera.Size> pictureSizes = params.getSupportedPictureSizes(); Camera.Size optimalPictureSize = getOptimalSize(pictureSizes, optimalPreviewSize.width, optimalPreviewSize.height); params.setPictureSize(optimalPictureSize.width, optimalPictureSize.height); mCamera.setParameters(params); } // 自定义方法:获取适配目标宽高的最优尺寸 private Camera.Size getOptimalSize(List<Camera.Size> sizes, int targetWidth, int targetHeight) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) targetWidth / targetHeight; Camera.Size optimalSize = null; double minDiff = Double.MAX_VALUE; for (Camera.Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } // 如果没找到比例匹配的,选高度最接近的 if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Camera.Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; }
额外提示
- 确保SurfaceView的Surface已经创建完成后再初始化相机,可以在
SurfaceHolder.Callback的surfaceCreated或surfaceChanged方法中调用initCamera()。 - 不要忽略
startPreview抛出的异常,捕获后做优雅降级(比如提示用户重启相机),提升用户体验。
内容的提问来源于stack exchange,提问作者Vivek Gabadiya
相关产品推荐
相关产品推荐

