Android Bitmap OutOfMemory问题

时间:2013-05-27 08:57:44

标签: android

我的应用程序将有超过350张图像,这些图像将从数据库中解码。我根据图像数据创建位图,并根据设备屏幕分辨率进行缩放。当我试图将所有这些位图保存到内存中时,我面临outOfMemory异常。然后在各个地方推荐使用BitmapFactory.Options.inPurgeable作为避免OutOfMemoryExceptions的方法。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
options.inInputShareable = true;

Bitmap bitmap = BitmapFactory.decodeByteArray(imagaeData, 0, size, options);
...
..
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, true); 

我将这个缩放的位图缓存到HashMap并将其用于图像视图。在将位图加载到内存时,我再次遇到OutOfMemory异常。我不知道inPurgeable是否适用于我的情况。我想知道缩放的位图是否会引用字节数组。当我使用缩放位图时,它是否具有decodeByteArray中使用的inPurgeable选项的效果。我无法弄清楚如何处理这个位图内存问题。感谢您的帮助。

4 个答案:

答案 0 :(得分:0)

350张图片非常多。你确定你一次需要它们吗?

另外:当你创建一个缩放的位图时,你将它们存储在内存中两次 - >内存中的700个图像太过分了。您应该检查是否最好在选项上使用inScale再次将其减少到350并减少内存占用量。

我仍然认为,即使在优化的方式中,350张图片太多了。您应该考虑延迟加载解决方案。

答案 1 :(得分:0)

您可以尝试使用BitmapFactory.Options.inScaled& BitmapFactory.Options。 inScreenDensity获取缩放的位图。

您需要一种更好的方法来缓存内存中的位图。你最好在HashMap中为位图保存Bitmap的WeakReference,你可以切换到LinkedHashMap来实现简单的LRU缓存。

你真的不需要缓存所有图像,因为它们永远不会有机会在一个屏幕上显示。

答案 2 :(得分:0)

哇,尝试在内存中同时保留350个位图听起来很疯狂。即使它们很小,我也不会推荐它。当然你不能同时显示所有这些位图,那么最后是否同时将所有这些位图保存在内存中呢?

你真的应该考虑使用类似Square's Picasso lib的东西来处理图像加载和缩放。 Picasso处理“ImageView回收并在适配器中下载取消”,“自动内存和磁盘缓存”以及“最小化内存使用的复杂图像转换”。

答案 3 :(得分:0)

使用此方法首先缩小图像尺寸(文件指向SD卡上的照片)

//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
    try {
        //decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        FileInputStream stream1=new FileInputStream(f);
        BitmapFactory.decodeStream(stream1,null,o);
        stream1.close();

        //Find the correct scale value. It should be the power of 2.
        // maximum size is 50
        final int REQUIRED_SIZE=40;
        int width_tmp=o.outWidth, height_tmp=o.outHeight;
        int scale=1;
        while(true){
            if(width_tmp/2<=REQUIRED_SIZE || height_tmp/2<=REQUIRED_SIZE)
                break;
            width_tmp/=2;
            height_tmp/=2;
            scale*=2;
        }

        //decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize=scale;
        FileInputStream stream2=new FileInputStream(f);
        Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
        stream2.close();
        return bitmap;
    } catch (FileNotFoundException e) {
    } 
    catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

//以下是调用上述方法的方法

                    String path = "/mnt/sdcard/DCIM/camera/IMG_2001.jpg";
                    Drawable background = hash_map.get(path);
                    if (background == null) {
                    try {
                        Bitmap bitmap = decodeFile(new File(path));
                        background = new BitmapDrawable(bitmap);
                        if (hash_map.size() > 600) {
                            // to prevent HashMap from growing too large.
                            hash_map.clear();
                        }
                        hash_map.put(path, background);
                    } catch (Throwable e) {
                        // in case there is an exception, like running out of memory.
                        if (e instanceof OutOfMemoryError) {
                            hash_map.clear();
                        }
                    }
                 }