【问题标题】:BitmapFactory.DecodeByteArray causing Grow Heap (frag case)BitmapFactory.DecodeByteArray 导致 Grow Heap (frag case)
【发布时间】:2014-10-17 08:55:05
【问题描述】:

我正在 Xamarin 中开发一个 Android 应用程序。我在从字节流生成图像时遇到问题。 BitmapFactory(这似乎是最流行的解决方案)正在导致巨大的分配问题 - Grow Heap。

        ConnectToDb connect = new ConnectToDb ();
        byte[] arr = connect.SelectImgByte(3,"Thea");

        BitmapFactory.Options options=new BitmapFactory.Options();
        options.InJustDecodeBounds = true;
        bmp = BitmapFactory.DecodeByteArray (arr, 0, arr.Length/*,options*/);
        _imageView.SetImageBitmap (bmp);

上面是调用 BitmapFactory.DecodeByteArray 的方法。它工作正常,显示图像。但它很慢并且会导致这些“警告”。

Thread started: <Thread Pool> #6
[dalvikvm-heap] Grow heap (frag case) to 22.596MB for 1997584-byte allocation
[Choreographer] Skipped 129 frames!  The application may be doing too much work on its main thread.
[dalvikvm-heap] Grow heap (frag case) to 20.755MB for 1997584-byte allocation
[dalvikvm-heap] Grow heap (frag case) to 22.735MB for 1997584-byte allocation
[dalvikvm-heap] Grow heap (frag case) to 24.710MB for 1997584-byte allocation

每次调用该方法时,都会出现 Grow Heap 错误。如您所见,我已将图像加载到 imageview 4 次。 所以,我想知道是否有人和我有同样的问题?我尝试了很多小时来解决这个问题,通过查看这里(以及其他地方),但我找不到解决方案。 请记住,我正在用 Xamarin(c# 语言 - 使用 Android 库)编写应用程序。

对不起,糟糕的链接,但我还没有足够的信誉在这里上传图片:)

【问题讨论】:

  • 请在帖子中包含您的代码,而不是链接到它的图片,链接将来可能会失效,这也会使帖子更难阅读。
  • 嗨,我需要 10 或更多的声望,所以我现在做不到。我在这里完全是新手,所以我的声誉仍然是 1 :)
  • 您可以在问题中发布文本,然后将其标记为代码,它将被正确格式化,这不需要任何信誉积分。
  • @TheaRasmussen 你想下载你的图片还是使用 Drawable 图片来显示????
  • 感谢您的提示!如您所见,我正在将图像添加到 ImageView - 所以我想使用可绘制图像来显示。

标签: c# android bitmap xamarin bytearray


【解决方案1】:

我看到的第一件事是您使用InJustDecodeBounds,通常用于获取图像的宽度和高度,如下所示:

var options = new BitmapFactory.Options {
    InJustDecodeBounds = true,
};
using (var derp = BitmapFactory.DecodeResource(Resources, 
    Resource.Id.myimage, options)) { }

var imageHeight = options.OutHeight;
var imageWidth  = options.OutWidth;

这通常用于在缩小图像之前获取图像的纵横比,而不是将巨大的图像加载到内存中。

如果您查看 Xamarin 文档中的 docs about loading large bitmaps efficiently,您会发现他们只是为此使用它。

然后他们确保在using 语句中加载Bitmap 并将其分配给ImageView,如下所示:

using(var bmp = DecodeBitmap(some args))
    imageView.SetImageBitmap(bmp);

如果您之后不需要Bitmap,您可以在其上调用Recycle(),这会告诉Java运行时摆脱它:

using(var bmp = DecodeBitmap(some args)) {
    imageView.SetImageBitmap(bmp);
    bmp.Recycle();
}

所以你需要做一些类似的事情,可能也用你的 byte 数组,因为它包含图像的所有像素。

因此,使用文档中的模式,您可以执行以下操作:

byte[] arr = connect.SelectImgByte(3,"Thea");

using(var bmp = DecodeSampledBitmapFromArray(arr, scaledWidth, scaledHeight)) {
    _imageView.SetImageBitmap(bmp);
    bmp.Recycle();
}

public static int CalculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight)
{
    // Raw height and width of image
    var height = (float)options.OutHeight;
    var width = (float)options.OutWidth;
    var inSampleSize = 1D;

    if (height > reqHeight || width > reqWidth)
    {
        inSampleSize = width > height
                            ? height/reqHeight
                            : width/reqWidth;
    }

    return (int) inSampleSize;
}

public static Bitmap DecodeSampledBitmapFromArray(byte[] pixels, int reqWidth, int reqHeight)
{
    var options = new BitmapFactory.Options {
        InJustDecodeBounds = true,
    };
    using (var dispose = BitmapFactory.DecodeResource(arr, 0, arr.Length, options)) { }

    // Calculate inSampleSize
    options.InSampleSize = CalculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.InJustDecodeBounds = false;
    return BitmapFactory.DecodeResource(arr, 0, arr.Length, options);
}

【讨论】:

  • 嗨@Cheesebaron。我要创建的图像来自字节流,并且在资源中找不到(所以我不能使用 Decoderesources)。当我拍照并保存它时,我已经在使用你的方法调用的结构。我也在缩小它。但这不是产生问题的结构,而是当我使用此方法 BitmapFactory.DecodeByteArray 时。如果我使用您的代码,仅使用 DecodeByteArray 进行修改,那么我会得到更多的 Grow Heap 错误,因为方法 DecodeByteArray 将被调用两次(在 DecodeSampledBitmapFromArray 中)。
猜你喜欢
  • 1970-01-01
  • 2012-12-04
  • 1970-01-01
  • 2014-09-18
  • 2012-05-25
  • 2013-06-06
  • 1970-01-01
  • 2020-12-16
  • 1970-01-01
相关资源
最近更新 更多