在进行位图处理时如何避免“内存不足异常”?

时间:2013-04-29 17:29:20

标签: android

onPictureTaken中,我想执行以下操作:

Bitmap decodedPicture = BitmapFactory.decodeByteArray(data, 0, data.length);
Matrix matrix = new Matrix();
matrix.preScale(-1.0f, 1.0f);
Bitmap picture = Bitmap.createBitmap(decodedPicture, 0, 0, decodedPicture.getWidth(), decodedPicture.getHeight(), matrix, false);

View v1 = mainLayout.getRootView();
v1.setDrawingCacheEnabled(true);
Bitmap screenshot = Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);

Bitmap scaledPicture = Bitmap.createScaledBitmap(picture, screenshot.getWidth(), screenshot.getHeight(), true);

Bitmap compos = Bitmap.createBitmap(scaledPicture.getWidth(), scaledPicture.getHeight(), Bitmap.Config.ARGB_8888);

Canvas canvas = new Canvas(compos);
canvas.drawBitmap(scaledPicture, new Matrix(), null);
canvas.drawBitmap(screenshot, new Matrix(), null);

MediaStore.Images.Media.insertImage(getContentResolver(), compos, "name" , "description");
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));

我唯一的要求是我想要保存高质量的照片......似乎我可能要牺牲它。

在我的Nexus 4和更新的设备上,此代码运行正常且符合预期。但是在内存较少的旧设备上,我的内存不足了! :(

如何在不超出内存限制的情况下进行相同的图像处理?我不是试图在屏幕上显示这些图像,因此与缩小图像有关的解决方案并不适用于此...

4 个答案:

答案 0 :(得分:3)

您需要使用增加的样本大小来读取位图。诀窍是找到正确的样本大小,在最终缩放图像时不会导致分辨率降低。我在这里写了一篇关于它的博客文章,其中包括一个很好的缩放实用程序类,

  

http://zerocredibility.wordpress.com/2011/01/27/android-bitmap-scaling/

根据您的具体需求,您可能会相当简化该课程。

jist只是读取位图的大小。根据您所需的缩放尺寸计算最佳样本大小,使用该样本大小读取位图,然后将其精确缩放到您想要的大小。

答案 1 :(得分:0)

你有很多Bitmap对象。尝试回收/重复使用其中一些。

不完全确定您的要求是什么,但我可以看到您可以通过简单地执行此操作来节省一些内存。

        Bitmap decodedPicture = BitmapFactory.decodeByteArray(data, 0, data.length);
        Matrix matrix = new Matrix();
        matrix.preScale(-1.0f, 1.0f);
        Bitmap picture = Bitmap.createBitmap(decodedPicture, 0, 0, decodedPicture.getWidth(), decodedPicture.getHeight(), matrix, false);

        decodedPicture.recycle();
        decodedPicture=null;

        View v1 = mainLayout.getRootView();
        v1.setDrawingCacheEnabled(true);
        Bitmap screenshot = Bitmap.createBitmap(v1.getDrawingCache());
        v1.setDrawingCacheEnabled(false);

        Bitmap scaledPicture = Bitmap.createScaledBitmap(picture, screenshot.getWidth(), screenshot.getHeight(), true);

        picture.recycle();
        picture=null;

        Bitmap compos = Bitmap.createBitmap(scaledPicture.getWidth(), scaledPicture.getHeight(), Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(compos);
        canvas.drawBitmap(scaledPicture, new Matrix(), null);
        canvas.drawBitmap(screenshot, new Matrix(), null);

        MediaStore.Images.Media.insertImage(getContentResolver(), compos, "name" , "description");
        sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));

另外,请查看您的内存占用情况,确保您使用的设备智能内存不是太大。

仅供参考,在本机层上分配的后honycomb设备位图像素图像上。您需要recycle()finalizer()来恢复内存

答案 2 :(得分:0)

考虑到你不想调整你的位图大小并且不想显示它,我会做这样的事情:

  1. 使用inJustDecodeBounds加载位图以查看其原始高度和宽度(代码来自here

    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);
    
    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    
  2. 根据您拥有的大小和内存,您可以直接从那里处理它(即加载位图)或继续使用允许您的Bitmap.createBitmap方法加载一些所述位图的块只加载一大块数据。可选:在处理块之前,考虑将其转换为字节数组(请参阅下面的代码)和null + recycle()

  3. <强>码

    ByteArrayOutputStream byteArrayBitmapStream = new ByteArrayOutputStream();
    bitmapPicture.compress(Bitmap.CompressFormat.PNG, COMPRESSION_QUALITY, byteArrayBitmapStream);
    byte[] b = byteArrayBitmapStream.toByteArray();
    

答案 3 :(得分:0)

我用于处理Bitmap类WeakReference,之后我总是在实例对象WeakReference上调用recycle,这是旋转图像的代码片段:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inPurgeable = true;
options.inInputShareable = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
WeakReference<Bitmap> imageBitmapReference = new WeakReference<Bitmap>(BitmapFactory.decodeByteArray(params[0], 0, params[0].length, options));

Matrix mat = new Matrix();
mat.postRotate(90.0f); 
imageBitmapReference = new WeakReference<Bitmap (Bitmap.createBitmap(imageBitmapReference.get(), 0, 0, resolution[0], resolution[1], mat, true));

FileOutputStream fos = new FileOutputStream(filename);
imageBitmapReference.get().compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
fos.close();
imageBitmapReference.get().recycle();

第二个解决方案如何使用Bitmap并且没有获得OutOfMemory Exception就是使用库Universal Image Loader

(当然是AndroidManifest属性中设置的第三个解决方案android:largeHeap =&#34; true&#34;真的不要使用这个属性)。

完美素材位于http://developer.android.com/training/displaying-bitmaps/index.html和视频https://www.youtube.com/watch?v=_CruQY55HOk