0

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

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

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

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

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

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

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

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

4

3 回答 3

2

Write a separate class for performing Custom Bitmap operations:

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);
}
}

Then from your activity, call Bitmap reqBitmap = loadBitmap(String filePath,int requiredWidth,int requiredHeight) method of this class providing the filepath of the bitmap obtained from the sd card, and setting the requiredWidth and requiredHeight to the dimensions you wish to scale the bitmap to. Now use the reqBitmap.

This way large bitmaps will be scaled down before they are loaded into the heap memory. I had the same problem and this solved it for me. :)

于 2012-10-22T12:37:23.127 回答
1

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

于 2012-10-22T13:52:06.177 回答
0

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

于 2013-02-27T22:38:40.790 回答