当我们自定义相机的时候有极少部分手机是会报错不支持图片预览的,报错位置如下:
camera.setParameters(p);
这是因为个别机型在SupportPreviewSizes里汇报了支持某种预览尺寸,但实际是不支持的
目前在小米6手机上出现这个问题:
会报如下错误:
SurfaceView: Exception configuring surface
java.lang.RuntimeException: setParameters failed
at android.hardware.Camera.native_setParameters(Native Method)
at android.hardware.Camera.setParameters(Camera.java:2262)
at com.wxdld.camear.CameraPreview.updateCameraParameters(CameraPreview.java:207)
at com.wxdld.camear.CameraPreview.surfaceCreated(CameraPreview.java:102)
at android.view.SurfaceView.updateSurface(SurfaceView.java:675)
at android.view.SurfaceView$2.onPreDraw(SurfaceView.java:143)
at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:977)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2522)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1505)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7354)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1092)
at android.view.Choreographer.doCallbacks(Choreographer.java:888)
at android.view.Choreographer.doFrame(Choreographer.java:819)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1078)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6810)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
解决方法是:在报错的地方
Camera.Parameters p = camera.getParameters(); setParameters(p); try { camera.setParameters(p); } catch (Exception e) { //个别机型在SupportPreviewSizes里汇报了支持某种预览尺寸,但实际是不支持的,设置进去就会抛出RuntimeException. Camera.Size previewSize = findBestPreviewSize(p); try { //遇到上面所说的情况,只能设置一个最小的预览尺寸 p.setPreviewSize(1920, 1080); // p.setPreviewSize(previewSize.width, previewSize.height); camera.setParameters(p); } catch (Exception e1) { //到这里还有问题,就是拍照尺寸的锅了,同样只能设置一个最小的拍照尺寸 e1.printStackTrace(); try { p.setPictureSize(1920, 1080); camera.setParameters(p); } catch (Exception ignored) { } } } }
其中findBestPreviewSize方法如下
/** * 找到最合适的显示分辨率 (防止预览图像变形) * * @param parameters * @return */ private Camera.Size findBestPreviewSize(Camera.Parameters parameters) { // 系统支持的所有预览分辨率 String previewSizeValueString = null; previewSizeValueString = parameters.get("preview-size-values"); if (previewSizeValueString == null) { previewSizeValueString = parameters.get("preview-size-value"); } if (previewSizeValueString == null) { // 有些手机例如m9获取不到支持的预览大小 就直接返回屏幕大小 return camera.new Size(CameraUtils.getScreenWH(getContext()).widthPixels, CameraUtils.getScreenWH(getContext()).heightPixels); } float bestX = 0; float bestY = 0; float tmpRadio = 0; float viewRadio = 0; if (viewWidth != 0 && viewHeight != 0) { viewRadio = Math.min((float) viewWidth, (float) viewHeight) / Math.max((float) viewWidth, (float) viewHeight); } String[] COMMA_PATTERN = previewSizeValueString.split(","); for (String prewsizeString : COMMA_PATTERN) { prewsizeString = prewsizeString.trim(); int dimPosition = prewsizeString.indexOf('x'); if (dimPosition == -1) { continue; } float newX = 0; float newY = 0; try { newX = Float.parseFloat(prewsizeString.substring(0, dimPosition)); newY = Float.parseFloat(prewsizeString.substring(dimPosition + 1)); } catch (NumberFormatException e) { continue; } float radio = Math.min(newX, newY) / Math.max(newX, newY); if (tmpRadio == 0) { tmpRadio = radio; bestX = newX; bestY = newY; } else if (tmpRadio != 0 && (Math.abs(radio - viewRadio)) < (Math.abs(tmpRadio - viewRadio))) { tmpRadio = radio; bestX = newX; bestY = newY; } } if (bestX > 0 && bestY > 0) { return camera.new Size((int) bestX, (int) bestY); } return null; }