繁体   English   中英

内存泄漏:带位图的ListView

[英]Memory Leaks : ListView with Bitmaps

我有明显的内存泄漏问题,需要一些帮助/建议来解决。

我的场景有一个简单的ListView,可以显示图像和标题。 该图像是从服务器下载的位图图像。

如此快速地上下滚动后,此ListView崩溃了我的应用程序,并且如果我检查控制台,则会遇到如下OOM异常:

[art] Clamp target GC heap from 111MB to 96MB
[art] Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 0% free, 95MB/96MB, paused 1.187ms total 38.840ms

为避免OOM,我实现了LRUCache和DiskCache来将下载的位图存储到设备中,并获取此文件,而不是再次下载图像。

这是我的ListView适配器:

public class LazyLoadAdapter : BaseAdapter
{
Activity _activity;
List _products;
BitmapCache cache;
ImageView _imgView;
Dictionary<string, Task> pendingFetch = new Dictionary<string, Task> ();
Bitmap NoMapPicture;

    public LazyLoadAdapter(Activity activity, List<CouponExchange> products)
    {
        _activity = activity;
        _products = products;
        NoMapPicture = PrepareNoMapPicture (Resource.Drawable.default_coupon);
        this.cache = BitmapCache.CreateCache (activity, "MapCache");
    }

    public override int Count
    {
        get { return _products.Count; }
    }

    public override Java.Lang.Object GetItem(int position)
    {
        return position;
    }

    public override long GetItemId(int position)
    {
        return position;
    }

    public override Android.Views.View GetView(int position, Android.Views.View convertView, Android.Views.ViewGroup parent)
    {
        if (convertView == null)
        {
            convertView = _activity.LayoutInflater.Inflate(Resource.Layout.ShopItemList, parent, false);
        }

        CouponExchange product = _products[position];

        TextView txtProductName = convertView.FindViewById<TextView>(Resource.Id.textView24);
        txtProductName.Text = product.CouponTitle;


        TextView txtProductCost = convertView.FindViewById<TextView>(Resource.Id.textView24b);
        txtProductCost.Text = product.Cost.ToString();

        _imgView = convertView.FindViewById<ImageView>(Resource.Id.imgProduct);

        GetPersonPicture (product.CouponImageUrl);

        return convertView;
    }


    Bitmap DownloadoCacher (string url)
    {
        Bitmap map = null;
        using(map){
            map = cache.TryGet2 (url);
            if (map!=null)
            return map;

        byte[] bytes;
        using (var wc = new WebClient ()) {
             bytes = wc.DownloadData (url);
        };

        if (bytes != null && bytes.Length > 0) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.InJustDecodeBounds = true;
            map = DecodeSampledBitmapFromResource (bytes, 400, 200);

        } else {
            return map;
        }
        cache.AddOrUpdate (url, map, TimeSpan.FromDays (1));
        return map;
        };
    }

    public static Bitmap DecodeSampledBitmapFromResource(byte[] bytes,
        int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.InJustDecodeBounds = true;
        BitmapFactory.DecodeByteArray(bytes, 0,  bytes.Length, options);

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

        // Decode bitmap with inSampleSize set
        options.InJustDecodeBounds = false;

        return BitmapFactory.DecodeByteArray(bytes, 0,  bytes.Length, options);
    }

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

        if (height > reqHeight || width > reqWidth) {

             int halfHeight = height / 2;
             int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

    Bitmap PrepareNoMapPicture (int baseImage)
    {
        return BitmapFactory.DecodeResource (_activity.Resources, baseImage);
    }


    Bitmap GetPersonPicture (string url){
        if (_imgView == null)
            return null;
        Bitmap map = null;
        using (map) {

            map = cache.TryGet2 (url);

        if (map!=null) {
            _imgView.SetImageBitmap (map);
        } else {
            _imgView.SetImageBitmap (NoMapPicture);
            Action doMapSetting = () => {
                _activity.RunOnUiThread (() => {
                    if (map == null){
                        map = cache.TryGet2 (url);
                    }
                    _imgView.SetImageBitmap (map);
                });
            };
            if (pendingFetch.ContainsKey (url))
                pendingFetch [url].ContinueWith (t => doMapSetting (), TaskContinuationOptions.ExecuteSynchronously);
            else
                pendingFetch[url] = SerialScheduler.Factory.StartNew (() => {
                    map = DownloadoCacher (url);
                    doMapSetting ();
                });
        }

        return map;
        };
    }

下载图像后,我的缓存会从设备文件中获取图像。 在如此快速地上下滚动之后,cacheDisk尝试从文件中获取图像并引发OOM异常:

 try {
            bmp = Android.Graphics.BitmapFactory.DecodeFile (Path.Combine (basePath, key));
    } catch (Exception e) {
            var err = e.Message;
            return null;
    }

所有答复将不胜感激。 谢谢

我将这个Picasso绑定库用于Xamarin: https : //github.com/jacksierkstra/Picasso

这个强大的图像下载和缓存库使您可以简化图像管理。

官方文档: http : //square.github.io/picasso/

希望这可以帮助

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM