BitmapFactory.decodeByteArray中的OutOfMemoryError用于三星Galaxy SII拍摄的照片

时间:2013-07-01 08:02:07

标签: android android-camera out-of-memory

我从OutOfMemoryError拍摄的照片中创建Bitmap时收到Camera。我的代码工作正常几次,直到我得到异常,所以我花了几个小时寻找内存泄漏。

奇怪的是,我将代码追溯到我的PictureCallback只是为了检查字节数组大小:当没有抛出异常时它大约为280k,但最终,我收到的字节数超过1.2M ,这就是decodeByteArray崩溃的时候。

我正在使用自定义CameraActivity。初始化Camera的代码如下所示

camera = Camera.open();
camera.setDisplayOrientation(cameraOrientation);            
Camera.Parameters params = camera.getParameters();
Size size = getPreferredPictureSize();
params.setPictureSize(size.width, size.height);
params.setJpegQuality(JPEG_QUALITY);
params.setPictureFormat(ImageFormat.JPEG);
camera.stopPreview();
camera.setParameters(params);
camera.startPreview();

当我的CameraActivity暂停时,我会像这样释放de Camera

if (camera != null) {
    camera.stopPreview();
    camera.release();
    camera = null;
}

为什么返回的图片在初始化相同的情况下会有如此不同的大小?我可能错过了一些完全释放Camera内容的方法吗?任何线索都表示赞赏:)

1 个答案:

答案 0 :(得分:0)

我实际上在这里发现了几个问题,但我设法通过每次拍照时重置我的相机参数来停止接收不同大小的数组。这是我的CameraUtils实现,以防有人发现它有用。

import java.util.List;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;

public class CameraUtils implements Camera.AutoFocusCallback {
    private static CameraUtils singleton = null;
    private Camera camera = null;
    private boolean isFocusing;
    private PictureCallback pictureCallback;
    private int cameraOrientation = 90; 
    private Size pictureSize;
    private final String CAMERA_FLASH_MODE_ON = "on";
    private final String CAMERA_FLASH_MODE_OFF = "off";
    private final int PHOTO_HEIGHT_THRESHOLD = 960;
    private final int JPEG_QUALITY = 90;    
    private String cameraFlashMode;
    private float defaultCameraRatio;

    private CameraUtils() {
    }

    public static CameraUtils getInstance() {
        if (singleton == null) {
            singleton = new CameraUtils();
        }

        return singleton;
    }

    @Override
    public void onAutoFocus(boolean success, Camera camera) {
        isFocusing = false;

        if (CAMERA_FLASH_MODE_ON.equals(cameraFlashMode)) {
            setFlashEnabled(true);
        }

        if (pictureCallback != null) {
            setupParameters();
            Application.getInstance().getCurrentActivity().showLoading();
            camera.takePicture(null, null, pictureCallback);
        }
    }

    public boolean checkCameraHardware() {
        if (Application.getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
            return true;
        } else {
            return false;
        }
    }

    public Camera getCamera() throws Exception {
        if (camera == null) {
            isFocusing = false;
            pictureCallback = null;
            camera = Camera.open();
            camera.setDisplayOrientation(cameraOrientation);
            setupParameters();
        }
        return camera;
    }

    public void setupParameters() {
        Camera.Parameters params = camera.getParameters();
        defaultCameraRatio = (float) params.getPictureSize().width / (float) params.getPictureSize().height;
        Size size = getPreferredPictureSize();
        params.setPictureSize(size.width, size.height);
        params.setJpegQuality(JPEG_QUALITY);
        params.setPictureFormat(ImageFormat.JPEG);    
        camera.stopPreview();
        camera.setParameters(params);
        camera.startPreview();
        pictureSize = size;
    }

    public void autofocus(boolean forceAutofocus) {
        if (camera != null && (!isFocusing || forceAutofocus)) {
            camera.cancelAutoFocus();
            disableFlash();
            isFocusing = true;
            camera.autoFocus(this);
        }
    }

    public void releaseCamera() {
        if (camera != null) {
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }

    public void setFlashEnabled(boolean enabled) {
        if (camera != null) {
            if (enabled) {
                if (camera.getParameters().getSupportedFlashModes().contains(CAMERA_FLASH_MODE_ON)) {
                    Camera.Parameters params = camera.getParameters();
                    params.setFlashMode(CAMERA_FLASH_MODE_ON);
                    camera.setParameters(params);

                    cameraFlashMode = CAMERA_FLASH_MODE_ON;
                }
            } else {
                if (camera.getParameters().getSupportedFlashModes().contains(CAMERA_FLASH_MODE_OFF)) {
                    Camera.Parameters params = camera.getParameters();
                    params.setFlashMode(CAMERA_FLASH_MODE_OFF);
                    camera.setParameters(params);

                    cameraFlashMode = CAMERA_FLASH_MODE_OFF;
                }
            }
        }
    }

    public void disableFlash() {
        Camera.Parameters params = camera.getParameters();
        params.setFlashMode(CAMERA_FLASH_MODE_OFF);
        camera.setParameters(params);
    }

    public void takePhoto(PictureCallback pictureCallback) throws Exception {
        this.pictureCallback = pictureCallback;
        autofocus(true);
    }

    private Size getPreferredPictureSize() {
        Size res = null;
        List<Size> sizes = camera.getParameters().getSupportedPictureSizes();

        for (Size s : sizes) {
            float ratio = (float) s.width / (float) s.height;
            if (ratio == defaultCameraRatio && s.height <= PHOTO_HEIGHT_THRESHOLD) {
                res = s;
                break;
            }
        }
        return res;
    }

    public Size getPictureSize() {
        return pictureSize;
    }   
}