这两天玩Android玩的废寝忘食,Blog都好几天没加东西了,惭愧!记录一下这两天最崩溃的一个问题。
好早就装了开发环境,真正着手还是这两天,非常的生疏,虽然有SDK文档,那么多蚊子一般的字,实在没心思慢慢研究。这不想调用摄像头,原以为很容易就能搞定的,累计花了大概有一天的时间才只能保证不出错……至于效果嘛,难说啊!
先看API-examples里有调用 摄像头的例子,在模拟器上虽然看不出什么效果,毕竟还是能执行的,就是一个方块在黑白相间的背景上移动呗。
就这么一个Google提供的范例,传到我的HTC G2上也能一执行就报错,我对Google的尊敬之情顿时减少了0.0001%啊……(当然有可能是G2不够标准,但毕竟其他的软件都是能用的,看来是有不少健壮代码了啊)。联机调试看了一下,出错的这一行(android-7里的):
parameters.setPreviewSize(w, h);
查一下,摄像头不是所有随便的(w, h)都能够认识的,所以呢,我们有了下面这样的增强版:
List<Size> mSupportedPreviewSizes; mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes(); mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height); private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) w / h; if (sizes == null) return null; Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (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); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; }
后来的Sample里有了这段代码,看起来强大了不少。然而非常不幸的,首先getSupportedPreviewSizes()这个函数在2.1之后才有,我一开始是打算用1.6开发的……好吧我改,这个先不说,自己的手机已经刷到2.1了,这个函数的返回值居然是null?!如果确实想老版本上也用的话,怎么办??
有鉴于有软件可以达成,所以肯定是有方法的!得这么写:
public class SupportedSizesReflect { private static Method Parameters_getSupportedPreviewSizes = null; private static Method Parameters_getSupportedPictureSizes = null; static { initCompatibility(); }; private static void initCompatibility() { try { Parameters_getSupportedPreviewSizes = Camera.Parameters.class.getMethod( "getSupportedPreviewSizes", new Class[] {}); Parameters_getSupportedPictureSizes = Camera.Parameters.class.getMethod( "getSupportedPictureSizes", new Class[] {}); } catch (NoSuchMethodException nsme) { nsme.printStackTrace(); Parameters_getSupportedPreviewSizes = Parameters_getSupportedPictureSizes = null; } } /** * Android 2.1之后有效 * @param p * @return Android1.x返回null */ public static List<Size> getSupportedPreviewSizes(Camera.Parameters p) { return getSupportedSizes(p, Parameters_getSupportedPreviewSizes); } public static List<Size> getSupportedPictureSizes(Camera.Parameters p){ return getSupportedSizes(p, Parameters_getSupportedPictureSizes); } @SuppressWarnings("unchecked") private static List<Size> getSupportedSizes(Camera.Parameters p, Method method){ try { if (method != null) { return (List<Size>) method.invoke(p); } else { return null; } } catch (InvocationTargetException ite) { Throwable cause = ite.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } else { throw new RuntimeException(ite); } } catch (IllegalAccessException ie) { return null; } } }
啊啊~,リフレクションなんか、大嫌い……然后还要用类似这样的方法调用~
@Override public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) { Camera.Parameters params = camera.getParameters(); List<Size> supportedPictureSizes = SupportedSizesReflect.getSupportedPictureSizes(params); List<Size> supportedPreviewSizes = SupportedSizesReflect.getSupportedPreviewSizes(params); if ( supportedPictureSizes != null && supportedPreviewSizes != null && supportedPictureSizes.size() > 0 && supportedPreviewSizes.size() > 0) { //2.x pictureSize = supportedPictureSizes.get(0); int maxSize = 1280; if(maxSize > 0){ for(Size size : supportedPictureSizes){ if(maxSize >= Math.max(size.width,size.height)){ pictureSize = size; break; } } } WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); DisplayMetrics displayMetrics = new DisplayMetrics(); display.getMetrics(displayMetrics); previewSize = getOptimalPreviewSize( supportedPreviewSizes, display.getWidth(), display.getHeight()); params.setPictureSize(pictureSize.width, pictureSize.height); params.setPreviewSize(previewSize.width, previewSize.height); } this.camera.setParameters(params); try { this.camera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } this.camera.startPreview(); }
死机无数次之后总结出来的啊,发现程序写的一个不好强制结束了,摄像头都无法再次启用了,kill都不行,只能重新启动手机才好。重启一次还那么慢,谁知道有比较适合G2的row?
哦还有一个,预览画面90°的,2.X后可以用parameters.set(“rotation”, “90”),之前的话得写成parameters.set(“orientation”, “portrait”)。但是据说不是所有的机器都可以的……
Pingback: 给Camera增加一个pictureSize选项 - Android - 开发者第911887个问答
大哥,你想要说什么??????????????????????????????
应该是 Android用摄像头的那点破事