1. Camera
Camera是Android framework里面支持的,允许你拍照和拍摄视频的设备,那么,在使用camera开发中总是会遇到一些问题,例如以下这样子的:
E/AndroidRuntime(1542): java.lang.RuntimeException: setParameters failed
E/AndroidRuntime(1542): at android.hardware.Camera.native_setParameters(Native Method)
E/AndroidRuntime(1542): at android.hardware.Camera.setParameters(Camera.java:914)
出现这种错误,根据错误提示我们可以知道是android的setParameters方法出错了。
2、那该如何解决呢?
我们知道camera的parameters中也有很多参数设置的,是哪个出错了呢?很多人不知所以然就上网开始找,找不到就开始各种猜测,一个个参数设置过去,其实最有效的方式是到底层找原因。ok,让我们打开android代码找到camera类。然后查找setParameters方法。
- private native final void native_setParameters(String params);
- /**
- * Changes the settings for this Camera service.
- *
- * @param params the Parameters to use for this Camera service
- * @throws RuntimeException if any parameter is invalid or not supported.
- * @see #getParameters()
- */
- public void setParameters(Parameters params) {
- native_setParameters(params.flatten());
- }
从这段代码中代码中,我们可以得到什么信息呢,setParameters方法是调用jni方法native_setParameters的方法,其实看到这里就差并不多了,因为再去查看jni方法是很麻烦的,毕竟我们日常开发使用大部分是java代码。我们可以发现传输进来的是Parameters参数,调用了 Parameters的flatten方法。我们查找flatten的代码进行查看。
- /**
- * Creates a single string with all the parameters set in
- * this Parameters object.
- * <p>The {@link #unflatten(String)} method does the reverse.</p>
- *
- * @return a String with all values from this Parameters object, in
- * semi-colon delimited key-value pairs
- */
- public String flatten() {
- StringBuilder flattened = new StringBuilder();
- for (String k : mMap.keySet()) {
- flattened.append(k);
- flattened.append("=");
- flattened.append(mMap.get(k));
- flattened.append(";");
- }
- // chop off the extra semicolon at the end
- flattened.deleteCharAt(flattened.length()-1);
- return flattened.toString();
- }
从这段代码中,我们又能得到什么信息呢。我们可以看到提供数据的时候,数据都是从mMap中获取的。ok,接下来,我们查看一下mMap是有几个方法对其进行了赋值呢。
- /**
- * Takes a flattened string of parameters and adds each one to
- * this Parameters object.
- * <p>The {@link #flatten()} method does the reverse.</p>
- *
- * @param flattened a String of parameters (key-value paired) that
- * are semi-colon delimited
- */
- public void unflatten(String flattened) {
- mMap.clear();
- StringTokenizer tokenizer = new StringTokenizer(flattened, ";");
- while (tokenizer.hasMoreElements()) {
- String kv = tokenizer.nextToken();
- int pos = kv.indexOf('=');
- if (pos == -1) {
- continue;
- }
- String k = kv.substring(0, pos);
- String v = kv.substring(pos + 1);
- mMap.put(k, v);
- }
- }
- /**
- * Sets a String parameter.
- *
- * @param key the key name for the parameter
- * @param value the String value of the parameter
- */
- public void set(String key, String value) {
- if (key.indexOf('=') != -1 || key.indexOf(';') != -1) {
- Log.e(TAG, "Key \"" + key + "\" contains invalid character (= or ;)");
- return;
- }
- if (value.indexOf('=') != -1 || value.indexOf(';') != -1) {
- Log.e(TAG, "Value \"" + value + "\" contains invalid character (= or ;)");
- return;
- }
- mMap.put(key, value);
- }
- /**
- * Sets an integer parameter.
- *
- * @param key the key name for the parameter
- * @param value the int value of the parameter
- */
- public void set(String key, int value) {
- mMap.put(key, Integer.toString(value));
- }
- private void set(String key, List<Area> areas) {
- if (areas == null) {
- set(key, "(0,0,0,0,0)");
- } else {
- StringBuilder buffer = new StringBuilder();
- for (int i = 0; i < areas.size(); i++) {
- Area area = areas.get(i);
- Rect rect = area.rect;
- buffer.append('(');
- buffer.append(rect.left);
- buffer.append(',');
- buffer.append(rect.top);
- buffer.append(',');
- buffer.append(rect.right);
- buffer.append(',');
- buffer.append(rect.bottom);
- buffer.append(',');
- buffer.append(area.weight);
- buffer.append(')');
- if (i != areas.size() - 1) buffer.append(',');
- }
- set(key, buffer.toString());
- }
- }
- /**
- * Returns the value of a String parameter.
- *
- * @param key the key name for the parameter
- * @return the String value of the parameter
- */
- public String get(String key) {
- return mMap.get(key);
- }
- /**
- * Sets the dimensions for preview pictures. If the preview has already
- * started, applications should stop the preview first before changing
- * preview size.
- *
- * The sides of width and height are based on camera orientation. That
- * is, the preview size is the size before it is rotated by display
- * orientation. So applications need to consider the display orientation
- * while setting preview size. For example, suppose the camera supports
- * both 480x320 and 320x480 preview sizes. The application wants a 3:2
- * preview ratio. If the display orientation is set to 0 or 180, preview
- * size should be set to 480x320. If the display orientation is set to
- * 90 or 270, preview size should be set to 320x480. The display
- * orientation should also be considered while setting picture size and
- * thumbnail size.
- *
- * @param width the width of the pictures, in pixels
- * @param height the height of the pictures, in pixels
- * @see #setDisplayOrientation(int)
- * @see #getCameraInfo(int, CameraInfo)
- * @see #setPictureSize(int, int)
- * @see #setJpegThumbnailSize(int, int)
- */
- public void setPreviewSize(int width, int height) {
- String v = Integer.toString(width) + "x" + Integer.toString(height);
- set(KEY_PREVIEW_SIZE, v);
- }
- /**
- * <p>Sets the dimensions for EXIF thumbnail in Jpeg picture. If
- * applications set both width and height to 0, EXIF will not contain
- * thumbnail.</p>
- *
- * <p>Applications need to consider the display orientation. See {@link
- * #setPreviewSize(int,int)} for reference.</p>
- *
- * @param width the width of the thumbnail, in pixels
- * @param height the height of the thumbnail, in pixels
- * @see #setPreviewSize(int,int)
- */
- public void setJpegThumbnailSize(int width, int height) {
- set(KEY_JPEG_THUMBNAIL_WIDTH, width);
- set(KEY_JPEG_THUMBNAIL_HEIGHT, height);
- }
- /**
- * Sets the quality of the EXIF thumbnail in Jpeg picture.
- *
- * @param quality the JPEG quality of the EXIF thumbnail. The range is 1
- * to 100, with 100 being the best.
- */
- public void setJpegThumbnailQuality(int quality) {
- set(KEY_JPEG_THUMBNAIL_QUALITY, quality);
- }
- /**
- * Sets Jpeg quality of captured picture.
- *
- * @param quality the JPEG quality of captured picture. The range is 1
- * to 100, with 100 being the best.
- */
- public void setJpegQuality(int quality) {
- set(KEY_JPEG_QUALITY, quality);
- }
- /**
- * Sets the rate at which preview frames are received. This is the
- * target frame rate. The actual frame rate depends on the driver.
- *
- * @param fps the frame rate (frames per second)
- * @deprecated replaced by {@link #setPreviewFpsRange(int,int)}
- */
- @Deprecated
- public void setPreviewFrameRate(int fps) {
- set(KEY_PREVIEW_FRAME_RATE, fps);
- }
- /**
- * Sets the maximum and maximum preview fps. This controls the rate of
- * preview frames received in {@link PreviewCallback}. The minimum and
- * maximum preview fps must be one of the elements from {@link
- * #getSupportedPreviewFpsRange}.
- *
- * @param min the minimum preview fps (scaled by 1000).
- * @param max the maximum preview fps (scaled by 1000).
- * @throws RuntimeException if fps range is invalid.
- * @see #setPreviewCallbackWithBuffer(Camera.PreviewCallback)
- * @see #getSupportedPreviewFpsRange()
- */
- public void setPreviewFpsRange(int min, int max) {
- set(KEY_PREVIEW_FPS_RANGE, "" + min + "," + max);
- }
- /**
- * Sets the image format for preview pictures.
- * <p>If this is never called, the default format will be
- * {@link android.graphics.ImageFormat#NV21}, which
- * uses the NV21 encoding format.</p>
- *
- * @param pixel_format the desired preview picture format, defined
- * by one of the {@link android.graphics.ImageFormat} constants.
- * (E.g., <var>ImageFormat.NV21</var> (default),
- * <var>ImageFormat.RGB_565</var>, or
- * <var>ImageFormat.JPEG</var>)
- * @see android.graphics.ImageFormat
- */
- public void setPreviewFormat(int pixel_format) {
- String s = cameraFormatForPixelFormat(pixel_format);
- if (s == null) {
- throw new IllegalArgumentException(
- "Invalid pixel_format=" + pixel_format);
- }
- set(KEY_PREVIEW_FORMAT, s);
- }
- /**
- * <p>Sets the dimensions for pictures.</p>
- *
- * <p>Applications need to consider the display orientation. See {@link
- * #setPreviewSize(int,int)} for reference.</p>
- *
- * @param width the width for pictures, in pixels
- * @param height the height for pictures, in pixels
- * @see #setPreviewSize(int,int)
- *
- */
- public void setPictureSize(int width, int height) {
- String v = Integer.toString(width) + "x" + Integer.toString(height);
- set(KEY_PICTURE_SIZE, v);
- }
- /**
- * Sets the image format for pictures.
- *
- * @param pixel_format the desired picture format
- * (<var>ImageFormat.NV21</var>,
- * <var>ImageFormat.RGB_565</var>, or
- * <var>ImageFormat.JPEG</var>)
- * @see android.graphics.ImageFormat
- */
- public void setPictureFormat(int pixel_format) {
- String s = cameraFormatForPixelFormat(pixel_format);
- if (s == null) {
- throw new IllegalArgumentException(
- "Invalid pixel_format=" + pixel_format);
- }
- set(KEY_PICTURE_FORMAT, s);
- }
ok,错误的地方,我们就定位在这么几个地方了。在自己写的代码里面,查看一下是否调用了这几个方法~~~。android源码还是注释得比较清晰的,看看方法英文说明,看是否参数有出现了错误。
当时我的是使用setPictureSize时出现了错误,根据方法说明,我简单解释下,为什么会出错。因为parameters.setPictureSize(320, 480)(设置分辨率)的参数有误,如果不清楚分辨率可以却掉这句话,再运行就OK了。
注:最后找了一下原因,感觉很简单,在实际 开发中,有时候一个小问题,就让人忙乎一个下午也是正常滴。