Android调用camera错误setParameters failed深层解析

本文详细解析了Android Camera在开发过程中遇到的setParameters失败问题,并提供了具体的解决方案,特别是针对setPictureSize方法的常见错误。

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了。 

注:最后找了一下原因,感觉很简单,在实际 开发中,有时候一个小问题,就让人忙乎一个下午也是正常滴。




<think> 首先,用户的问题是:“我想查找解决 java.lang.RuntimeException: setParameters failed 错误的方法”。用户提供了几个引用,我需要基于这些引用回答。 引用内容总结: - 引用[1]: 提到错误通常由于无效参数、不支持功能或资源冲突引起。解决方案包括确保参数有效、检查设备支持、处理资源冲突。 - 引用[2]: 提到设置预览或图片大小失败,可能是设备不兼容。解决方案是确保使用支持的尺寸。 - 引用[3]: 提到摄像头ID无效,需要在不同API级别兼容处理,设置尺寸时需检查支持。 - 引用[4]: 展示了代码示例,设置图片和预览尺寸,并旋转摄像头。 用户指令: - 系统级指令:确保数学表达式格式正确(但这里可能不涉及),使用中文回答,生成相关问题,引用标识添加在段落末尾。 - 用户可见层:回答结构清晰,逐步解决问题,保证真实可靠。 回答结构: - 由于用户要求“查找解决...错误的方法”,我需要提供步骤或方法。 - 基于引用,错误主要与相机参数设置相关。 - 步骤应清晰,逐步解释。 关键点: 1. **原因分析**:从引用看,错误可能由于: - 无效参数(如分辨率、对焦模式等)。 - 不支持的相机功能。 - 相机资源冲突。 - 设备不兼容或尺寸设置错误。 - API级别兼容问题。 2. **解决方案**: - 确保参数有效:检查设置的尺寸是否被设备支持(使用`getSupportedPreviewSizes()`和`getSupportedPictureSizes()`)。 - 处理API兼容:在不同Android版本上正确处理摄像头ID和参数。 - 避免资源冲突:确保只有一个应用访问相机。 - 错误处理:添加异常捕获。 逐步解决方法: 1. **检查参数有效性**:在设置参数前,获取支持的尺寸列表,并选择支持的尺寸。 2. **API兼容性**:处理不同API级别的摄像头访问。 3. **资源管理**:释放相机资源。 4. **错误处理**:捕获异常并提供回退。 生成相关问题: - 根据指令:“生成相关问题”,在回答末尾添加相关问题。 - 相关问题应与主题相关,如调试技巧、优化方法等。 引用标识: - 在回答中引用的部分末尾添加引用标识,如[^1]。 完整回答: - 开头:直接回应问题。 - 主体:逐步解释解决方法。 - 结尾:生成相关问题。 最终回答框架: 1. 介绍错误原因。 2. 逐步解决方案。 3. 代码示例(可选)。 4. 相关问题。 </think>### 解决 java.lang.RuntimeException: setParameters failed 错误的方法 `java.lang.RuntimeException: setParameters failed`是Android开发中常见的相机相关错误,通常发生在调用`setParameters()`方法设置相机参数时失败。根据引用分析错误主要源于无效参数、设备兼容性问题、资源冲突或API级别差异[^1][^3]。以下是结构化的解决方法,基于实际开发经验逐步操作: #### 1. **检查参数有效性** - **问题原因**:设置的分辨率、对焦模式、曝光等参数无效或不被设备支持(如引用[1]所述)。 - **解决步骤**: - 使用`getSupportedPreviewSizes()`和`getSupportedPictureSizes()`获取设备支持的尺寸列表。 - 从中选择有效的尺寸再设置。例如: ```java Camera.Parameters parameters = mCamera.getParameters(); List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes(); List<Camera.Size> supportedPictureSizes = parameters.getSupportedPictureSizes(); // 选择第一个支持的尺寸作为默认值(或根据需求选择) if (!supportedPreviewSizes.isEmpty()) { parameters.setPreviewSize(supportedPreviewSizes.get(0).width, supportedPreviewSizes.get(0).height); } if (!supportedPictureSizes.isEmpty()) { parameters.setPictureSize(supportedPictureSizes.get(0).width, supportedPictureSizes.get(0).height); } mCamera.setParameters(parameters); // 确保在设置前验证 ``` - 避免直接硬编码尺寸(如引用[2]中的`setPreviewSize(previewList.get(2).width, pictureList.get(2).height)`),这可能导致设备不兼容。 - **注意事项**:测试不同尺寸组合,设备可能不支持某些宽高比[^3]。 #### 2. **处理API兼容性和摄像头ID** - **问题原因**:Android不同版本(API 9、14、21等)对摄像头ID的处理不同,前摄/后摄判断错误会导致参数设置失败(如引用[3]所述)。 - **解决步骤**: - 使用`Camera.getNumberOfCameras()`获取可用摄像头数量。 - 根据API级别选择摄像头ID: ```java int mCameraId = -1; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // API 21+ 使用Camera2 API更稳定 mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK; // 默认后摄 } else { // 旧API版本遍历摄像头 for (int i = 0; i < Camera.getNumberOfCameras(); i++) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(i, info); if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { mCameraId = i; break; } } } mCamera = Camera.open(mCameraId); // 打开指定摄像头 ``` - 在设置参数前添加旋转处理(如引用[4]中的`parameters.setRotation(90)`),但需检查设备是否支持该旋转值。 - **注意事项**:在`AndroidManifest.xml`中添加必要的权限(如`<uses-permission android:name="android.permission.CAMERA"/>`)。 #### 3. **解决资源冲突和释放资源** - **问题原因**:多个应用同时访问相机或资源未释放(如引用[1]所述)。 - **解决步骤**: - 确保单例访问:在`onResume()`中打开相机,在`onPause()`中释放: ```java @Override protected void onPause() { super.onPause(); if (mCamera != null) { mCamera.release(); // 释放相机资源 mCamera = null; } } ``` - 添加异常捕获:在`setParameters()`调用处包裹`try-catch`块: ```java try { mCamera.setParameters(parameters); } catch (RuntimeException e) { Log.e("CameraError", "setParameters failed: " + e.getMessage()); // 回退到默认参数或重试 } ``` - **注意事项**:使用`SurfaceView`时,确保在`surfaceCreated()`中初始化相机,避免预览配置冲突(如引用[2])。 #### 4. **测试和回退策略** - **验证方法**:在真机上测试(不同设备可能行为不同),使用Logcat查看详细错误日志。 - **回退方案**:如果设置失败,回退到默认参数: ```java if (mCamera != null) { parameters = mCamera.getParameters(); // 获取默认参数 // 仅设置必要参数(如旋转) parameters.setRotation(90); mCamera.setParameters(parameters); } ``` 通过以上步骤,大多数`setParameters failed`错误可解决。如果问题持续,检查Android版本和设备型号,考虑使用Camera2 API(Android 5.0+)替代旧Camera API以提高兼容性[^4]。
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值