我正试图找出多年来为什么我在listview的视图中出现了这个内存泄漏。
奇怪的是,当使用((BitmapDrawable)_activity.Resources.GetDrawable(Resource.Drawable.splash))。Bitmap设置imageview(coverIv)时,根本没有问题。
当我使用await ImageLoader.DecodeSampledBitmapFromResourceAsync(localImageLocation,imgWidth,imgHeight)时,每次在listview中滚动一点时都会出现巨大的内存泄漏
我尝试使用内存分析器工具查找引用但没有...虽然MAT说问题是位图
public void ImageLoaded(string localImageLocation)
{
int screenWidth = _activity.Resources.DisplayMetrics.WidthPixels;
int imgWidth = screenWidth - (int)ConvertDpToPix (32f);
int imgHeight = (int)(ConvertDpToPix(206f));
BundleProgress.Visibility = ViewStates.Gone;
if (CoverIv.Drawable != null)
{
((BitmapDrawable)CoverIv.Drawable).Bitmap.Recycle ();
((BitmapDrawable)CoverIv.Drawable).Bitmap.Dispose ();
CoverIv.SetImageDrawable (null);
}
CoverIv.SetImageBitmap
(
//MEMORYLEAK: await ImageLoader.DecodeSampledBitmapFromResourceAsync (localImageLocation, imgWidth, imgHeight)
((BitmapDrawable)_activity.Resources.GetDrawable(Resource.Drawable.splash)).Bitmap
);
ImageLoader类中的方法:
public static async Task<Bitmap> DecodeSampledBitmapFromResourceAsync (String path,int reqWidth, int reqHeight)
{
// First decode with inJustDecodeBounds=true to check dimensions of the image
BitmapFactory.Options options = new BitmapFactory.Options();
options.InJustDecodeBounds = true;
Bitmap bitmap = await BitmapFactory.DecodeFileAsync(path, options);
// Calculate inSampleSize
options.InSampleSize = CalculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.InJustDecodeBounds = false;
options.InPreferredConfig = Bitmap.Config.Argb8888;
//options.InDither = true;
return await BitmapFactory.DecodeFileAsync(path, options);
}
public static int CalculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight)
{
// Raw height and width of image
float height = options.OutHeight;
float width = options.OutWidth;
double inSampleSize = 1D;
if (height > reqHeight || width > reqWidth)
{
int halfHeight = (int)(height / 2);
int halfWidth = (int)(width / 2);
// Calculate a inSampleSize that is a power of 2 - the decoder will use a value that is a power of two anyway.
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth)
{
inSampleSize *= 2;
}
}
return (int)inSampleSize;
}
适配器:
public override View GetView (int position, View convertView, ViewGroup parent)
{
BaseBundelVO bundle = _bundles [position];
DSBundleListItem bundleHolder = null;
DSBundleArchiveItem archiveHolder = null;
int type = GetItemViewType(position);
if (convertView == null)
{
bundleHolder = new DSBundleListItem (_activity.ApplicationContext);
archiveHolder = new DSBundleArchiveItem (_activity.ApplicationContext);
switch (type)
{
case 0:
convertView = _activity.LayoutInflater.Inflate (Resource.Layout.dsBundleListItem, null);
bundleHolder.IconIv = convertView.FindViewById<ImageView> (Resource.Id.iconIv);
bundleHolder.CoverIv = convertView.FindViewById<ImageView> (Resource.Id.coverIv);
bundleHolder.CoverTitleTv = convertView.FindViewById<TextView> (Resource.Id.coverTitleTv);
bundleHolder.CoverSubTitleTv = convertView.FindViewById<TextView> (Resource.Id.coverSubTitleTv);
bundleHolder.BundleProgress = convertView.FindViewById<ProgressBar> (Resource.Id.bundleProgress);
convertView.Tag = bundleHolder;
break;
case 1:
convertView = _activity.LayoutInflater.Inflate (Resource.Layout.dsBundleArchiveItem, null);
archiveHolder.ArchiveTitleTv = convertView.FindViewById<TextView> (Resource.Id.archiveTitleTv);
archiveHolder.ArchiveSubTitleTv = convertView.FindViewById<TextView> (Resource.Id.archiveSubTitleTv);
convertView.Tag = archiveHolder;
break;
}
}
else
{
switch (type)
{
case 0:
bundleHolder = (DSBundleListItem)convertView.Tag;
break;
case 1:
archiveHolder = (DSBundleArchiveItem)convertView.Tag;
break;
}
}
switch (type)
{
case 0:
bundleHolder.CoverTitleTv.Text = bundle.Title;
bundleHolder.CoverSubTitleTv.Text = bundle.SubTitle;
bundleHolder.CoverIv.SetImageDrawable (null);
bundleHolder.IconIv.SetImageDrawable (null);
bundleHolder.LoadImage(bundle.CoverImageLocation,bundle.Icon);
break;
case 1:
archiveHolder.ArchiveTitleTv.Text = "Archief";
archiveHolder.ArchiveSubTitleTv.Text = "Bekijk onze eerder verschenen publicaties";
break;
}
return convertView;
}
public void SetData(List<BaseBundelVO> bundles)
{
_bundles.Clear ();
_bundles.AddRange(bundles);
}
答案 0 :(得分:0)
使用图片时使用the picasso library,它可以创造奇迹!
答案 1 :(得分:0)
我也推荐Pisasso图书馆。 这是链接:http://square.github.io/picasso/
它立即从网上检索图像并在本地缓存它。
导入Picasso库后,您只需将此行添加到代码中:
Picasso.with(context).load("*your url*").into(*your image view*);
您也可以加载本地图像!
Picasso.with(context).load("file:///android_asset/image.png").into(*your image view*);
希望这会有所帮助,
答案 2 :(得分:0)
请尝试我的代码。我认为你的解码有问题:
private Bitmap DisplayRotatedPhoto(Uri path) {
String filePath = path.toString().substring(8);
Bitmap oriented = null;
BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();
bitmapFactoryOptions.inJustDecodeBounds = true;
int REQUIRED_SIZE = 100;
int width_tmp = bitmapFactoryOptions.outWidth, height_tmp = bitmapFactoryOptions.outHeight;
int scale = 2;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale++;
}
BitmapFactory.Options bitmapFactoryOptions2 = new BitmapFactory.Options();
bitmapFactoryOptions2.inSampleSize = scale;
Bitmap bmp = BitmapFactory.decodeFile(filePath, bitmapFactoryOptions2);
}