【问题标题】:Android bitmaps reuseAndroid 位图复用
【发布时间】:2012-10-12 06:17:50
【问题描述】:

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

好处是我不需要同时使用所有位图。

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

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

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

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

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

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

【问题讨论】:

  • “我尝试了 recycle() 方法调用,虽然我知道它已经过时了,因为位图的内存现在驻留在堆上,而不是本机内存上。”。从 Android 3.2 开始就是这样
  • 是的!我在 Android 4.0 中的目标!

标签: java android bitmap garbage-collection reusability


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢你,vickey,但我已经这样做了,但这还不够……仍然出现 OutOfMemory 异常。我需要一些能让我有可能重用像素缓冲区或其他东西的东西。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-16
      • 2011-10-22
      • 2012-09-30
      • 2014-04-01
      • 2016-11-05
      • 1970-01-01
      • 2011-10-13
      • 2014-09-01
      相关资源
      最近更新 更多