在Android应用程序上创建位图时OOM



我有一个应用程序,它从相机预览中获取固定数量的图像,并将它们转换为Bitmaps列表。为此,我有以下代码:

private Camera.PreviewCallback SetPreviewCallBack() {
    return new Camera.PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
    List<Bitmap> imageList = new ArrayList<Bitmap>();
    for (int i=0; i<30; i++) // Let's suppose this is the real loop. 
                             // It's not, as the real loop takes each camera preview frame, 
                             // instead of inserting the same one 30 times. 
                             // But for this example, it's OK
    {
        imageList.add(GetBitmap(
                    data, 
                    previewWidth, // Calculated
                    previewHeight, // Calculated 
                    previewFormat, // Calculated
                    previewRotation)); // Calculated
    }
}
private Bitmap GetBitmap(byte[] data, int width, int height, int previewFormat, int rotation) { 
    YuvImage yuv = new YuvImage(data, previewFormat, width, height, null);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    yuv.compressToJpeg(new Rect(0, 0, width, height), 50, out);
    byte[] bytes = out.toByteArray();
    final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
    Bitmap imageResult = RotateImage(bitmap, 4 - rotation);
    bitmap.recycle();
    return imageResult;
} 
private Bitmap RotateImage(Bitmap rotateImage, int rotation) {
    Matrix matrix = new Matrix();
    switch (rotation) {
    case 1:
        matrix.postRotate(270);
        break;
    case 2:
        matrix.postRotate(180);
        break;
    case 3:
        matrix.postRotate(90);
        break;
    }
    return Bitmap.createBitmap(rotateImage, 0, 0, rotateImage.getWidth(),
            rotateImage.getHeight(), matrix, true);
}

我所做的是:-我将此映像存储在Singleton类上,以便从同一应用程序中包含的另一个Activity访问它。-我再次调用这段代码(当某个事件发生时),并重复图像提取/保存过程。

03-05 09:35:13.339: E/AndroidRuntime(8762): FATAL EXCEPTION: Thread-818
03-05 09:35:13.339: E/AndroidRuntime(8762): java.lang.OutOfMemoryError
03-05 09:35:13.339: E/AndroidRuntime(8762):     at android.graphics.Bitmap.nativeCreate(Native Method)
03-05 09:35:13.339: E/AndroidRuntime(8762):     at android.graphics.Bitmap.createBitmap(Bitmap.java:726)
03-05 09:35:13.339: E/AndroidRuntime(8762):     at android.graphics.Bitmap.createBitmap(Bitmap.java:703)
03-05 09:35:13.339: E/AndroidRuntime(8762):     at android.graphics.Bitmap.createBitmap(Bitmap.java:636)
03-05 09:35:13.339: E/AndroidRuntime(8762):     at com.facephi.sdk.ui.CameraPreview.RotateImage(CameraPreview.java:779)
03-05 09:35:13.339: E/AndroidRuntime(8762):     at com.facephi.sdk.ui.CameraPreview.GetBitmap(CameraPreview.java:712)

我正试图使用最佳实践以正确的方式删除这里发布的未使用的Bitmaps,但运气不好。。。

你知道我为什么会出现OOM错误吗?

您在Android中的内存非常有限,这就是为什么会出现此异常。一般来说,你不应该在内存中存储太多图像,只应该在需要时加载它们(即显示它们或对它们做一些事情),并且应该在处理完它们后立即处理它们(recycle())。此外,您应该只以尽可能低的分辨率加载它们。

说了所有这些,但不知道为什么必须将它们全部存储在内存中(你可能有正当的理由),你可以通过在清单中指定适当的属性来增加应用程序的堆大小(http://developer.android.com/guide/topics/manifest/application-element.html#largeHeap)但即便如此,也不能保证你能加载太多的图像。

请记住,默认情况下,Android将为您的图像使用每像素4字节,因此,如果您有30张图像,每张图像的像素密度为100万,则您将使用1.2亿字节或大约120MB的内存。相比之下,应用程序的默认分配字节可能低至微不足道的16mb(取决于许多情况。请参阅此处了解更多详细信息:不同手机/设备和操作系统版本上的Android堆大小)。

如果您可以以某种方式更改代码,使它们不必全部加载到内存中,那么您可以查看位图缓存(http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html)这可以极大地帮助您解决内存管理问题。

1.尝试使用

BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 8;
options.inDither = false;
options.inPurgeable = true;
options.inInputShareable = true;
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);

这将大大有助于节省内存。

2.不要将Bitmap对象"存储"在singleton或其他任何地方。这将始终导致OutOfMemoryError。每次你想使用Bitmap时都要重新创建它。

编辑:

另请参阅官方的ThreadSample示例和高效显示位图教程。

最新更新