Android位图重用

时间:2012-10-22 12:24:37

标签: java android bitmap garbage-collection reusability

我是Android的新手! 我的Android SDK有一些很大的问题,因为我正在开发一个使用巨大位图(> 1200 * 1000)的应用程序,问题是在应用程序中我需要多个相同大小的图层/位图(其中3-5个) )。问题是内存堆在其中一个分配上被非常快速地消耗,并且触发了OutOfMemory异常。

好的部分是我不需要同时使用所有位图。

我尝试使用recycle()方法调用,虽然我知道它已经过时了,因为位图的内存现在驻留在堆上,而不是在本机内存上。 我还尝试从特定位图中删除所有引用,甚至手动调用System.gc()但没有用,无法删除位图。 好吧,也许会有内存泄漏我不知道,虽然我对此表示怀疑。

我尝试了各种各样的解决方案,但都没有。

对我来说最好的选择是重用一个位图,但BitmapFactory的解码方法只知道分配一个消耗内存的新Bitmap。

我的问题是,你知道一种重用位图像素的方法(覆盖位图的像素而不分配另一个位图/像素数组)可以用于Android ???问题是我无法驻留在GarbageCollector解决方案上,因为当我必须确定那些位图从内存中移除/其他位图不会被分配时,我的应用程序中有特定的时刻。

另一个解决方案是:你知道一种直接在SD卡上绘制一些位图的方法,而不通过堆内存吗?当我尝试分配一个大位图(原始大小的两倍)来连接两个其他处理过的位图时,它崩溃了...这就是我要问的原因。是否有可能直接从数据流中实例化Canvas r其他绘图对象?

其他解决方案是使用类似虚拟交换内存的东西,它可以模拟堆内存,但可以在SDCARD上进行缓存。但也找不到这样做的方法。

3 个答案:

答案 0 :(得分:2)

编写一个单独的类来执行自定义位图操作:

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;


class BitmapLoader
{
public static int getScale(int originalWidth,int originalHeight,
   final int requiredWidth,final int requiredHeight)
{
    //a scale of 1 means the original dimensions 
    //of the image are maintained
    int scale=1;

    //calculate scale only if the height or width of 
    //the image exceeds the required value. 
    if((originalWidth>requiredWidth) || (originalHeight>requiredHeight)) 
    {
        //calculate scale with respect to
        //the smaller dimension
        if(originalWidth<originalHeight)
            scale=Math.round((float)originalWidth/requiredWidth);
        else
          scale=Math.round((float)originalHeight/requiredHeight);

    }

    return scale;
}

public static BitmapFactory.Options getOptions(String filePath,
        int requiredWidth,int requiredHeight)
{

    BitmapFactory.Options options=new BitmapFactory.Options();
    //setting inJustDecodeBounds to true
    //ensures that we are able to measure
    //the dimensions of the image,without
    //actually allocating it memory
    options.inJustDecodeBounds=true;

    //decode the file for measurement
    BitmapFactory.decodeFile(filePath,options);

    //obtain the inSampleSize for loading a 
    //scaled down version of the image.
    //options.outWidth and options.outHeight 
    //are the measured dimensions of the 
    //original image
    options.inSampleSize=getScale(options.outWidth,
            options.outHeight, requiredWidth, requiredHeight);

    //set inJustDecodeBounds to false again
    //so that we can now actually allocate the
    //bitmap some memory
    options.inJustDecodeBounds=false;

    return options;

}



public static Bitmap loadBitmap(String filePath,
        int requiredWidth,int requiredHeight){


    BitmapFactory.Options options= getOptions(filePath,
            requiredWidth, requiredHeight);

    return BitmapFactory.decodeFile(filePath,options);
}
}

然后,从您的活动中,调用此类的Bitmap reqBitmap = loadBitmap(String filePath,int requiredWidth,int requiredHeight)方法,提供从sd卡获取的位图的filepath,并将requiredWidth和requiredHeight设置为您希望将位图缩放到的尺寸。现在使用reqBitmap

这样,大型位图在加载到堆内存之前将按比例缩小。我有同样的问题,这解决了我。 :)

答案 1 :(得分:1)

我遇到过类似的问题,recycle()对我不起作用。所以我做了一些像集myBitmap = null那样微不足道的事情。这向垃圾收集器指示myBitmap已被解除引用并且不再需要它。因此它将完成释放堆的工作。然后,您可以继续使用myBitmap加载新的位图,而不会出现内存异常。

答案 2 :(得分:0)

这可能为时已晚,但我建议使用“BitmapFactory.Options.inBitmap”。如果设置,skia将尝试重新使用此位图来解码图像。 http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inBitmap