2015-05-26 4 views
1

У меня проблема с утечкой памяти, и мне нужна помощь/советы для ее решения.Утечки памяти: ListView с растровыми изображениями

В моем сценарии есть простой ListView, который отображает изображение и заголовок. Это изображение является растровым изображением, загруженным с сервера.

После прокрутки вверх и вниз так быстро это ListView разбивает мое приложение, и если я проверить консоль у меня есть ОЫЙ Exception подобные:

[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 попытаться получить изображения из файлов и бросает ООМ Исключение:

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

Все ответы будут ценить. Спасибо Вам

+0

Так что это проблема, вы, кажется, ответили на свой вопрос – gerrytan

+0

Проблемы в том, что мое приложении падает на из памяти, несмотря на то, реализованный кэш изображения на диск. Я хочу знать, почему :( –

+2

Вы никогда не избавляетесь от изображения, возможно, поэтому. – Cheesebaron

ответ

2

Я использую эту Binding библиотеку Пикассо для Xamarin: https://github.com/jacksierkstra/Picasso

Это мощный образ загрузки и библиотека кэширование позволяет упростить управление изображения.

Официальная документация: http://square.github.io/picasso/

Надеется, что это помогает