我有明显的内存泄漏问题,我需要一些帮助/建议来解决它。
我的场景有一个简单的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;
}
所有回复都会很感激。谢谢你
答案 0 :(得分:2)
我将这个Picasso Binding库用于Xamarin: https://github.com/jacksierkstra/Picasso
这个功能强大的图像下载和缓存库可让您简化图像管理。
官方文件: http://square.github.io/picasso/
希望这有帮助