我正在尝试使用Xamarin.Android实现一个简单的自定义图库来显示我手机的所有照片。 为此,我使用带有适配器的Gridview并使用
创建缩略图MediaStore.Images.Thumbnails.GetThumbnail
但这种方法对于大量照片来说速度很慢,所以我创建了一个Task以使其异步。另外在GetView方法上添加CancellationToken以并行取消多个相同的任务。
但是出了点问题,我的应用程序在没有消息或有时“ outofmemory exeception ”的情况下崩溃。
已编辑的代码
这是我的适配器:
public class ImageAdapter : BaseAdapter
{
public bool IsScrolling = false;
private LayoutInflater mInflater;
private Context mContext;
private ICursor cursorImage;
private ViewHolder selectedItem;
private Bitmap blanckBitmap;
public ImageAdapter(Context context)
{
mInflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
mContext = context;
String[] columns = { MediaStore.Images.Media.InterfaceConsts.Id, MediaStore.Images.Media.InterfaceConsts.DateTaken };
String orderBy = MediaStore.Images.Media.InterfaceConsts.DateTaken + " DESC";
cursorImage = Application.Context.ContentResolver.Query(
MediaStore.Images.Media.ExternalContentUri,
columns,
null,
null,
orderBy);
blanckBitmap = Bitmap.CreateBitmap(100, 100, Bitmap.Config.Argb4444);
}
public override int Count => cursorImage.Count;
public override Java.Lang.Object GetItem(int position)
{
return position;
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
CancellationTokenSource cts;
if (convertView == null)
{
holder = new ViewHolder();
convertView = mInflater.Inflate(Resource.Layout.gallery_item, parent, false);
holder.Imageview = (ImageView)convertView.FindViewById(Resource.Id.gallery_item_thumbImage);
}
else
{
holder = (ViewHolder)convertView.Tag;
if (holder != null)
{
var wraper = holder.WrapperCancellation.JavaCast<Wrapper<CancellationTokenSource>>();
wraper?.Data.Cancel();
holder.WrapperCancellation = wraper;
}
}
holder?.Imageview.SetImageBitmap(blanckBitmap); // Set blanck bitmap
if (holder != null && !IsScrolling)
{
holder.Imageview.Id = position;
cts = new CancellationTokenSource();
GetImageThumbnailAsync(holder.Imageview, position, cts.Token);
holder.WrapperCancellation = new Wrapper<CancellationTokenSource> { Data = cts };
if (!holder.Imageview.HasOnClickListeners)
{
holder.Imageview.Click += (sender, args) =>
{
if (selectedItem != null)
{
selectedItem.Imageview.CropToPadding = false;
selectedItem.Imageview.Background = null;
}
selectedItem = holder;
holder.Imageview.CropToPadding = true;
holder.Imageview.Background = mContext.GetDrawable(Resource.Drawable.image_border_selected);
};
}
}
convertView.Tag = holder;
return convertView;
}
private async Task GetImageThumbnailAsync(ImageView imageView, int imgIndex, CancellationToken ct)
{
var bmp = await Task.Run(() =>
{
if (ct.IsCancellationRequested)
return null;
cursorImage.MoveToPosition(imgIndex);
var columnIndex = cursorImage.GetColumnIndex(MediaStore.Images.Media.InterfaceConsts.Id);
var id = cursorImage.GetInt(columnIndex);
return MediaStore.Images.Thumbnails.GetThumbnail(
Application.Context.ContentResolver,
id,
ThumbnailKind.MiniKind,
null);
}, ct);
if (!ct.IsCancellationRequested)
{
if (bmp != null)
imageView.SetImageBitmap(bmp);
}
}
}
GetImageThumbnailAsync 从GetView位置检索缩略图。
现在是ViewHolder类:
public class ViewHolder : Java.Lang.Object
{
public ImageView Imageview;
public int Id;
public Wrapper<CancellationTokenSource> WrapperCancellation;
}
public class Wrapper<T> : Java.Lang.Object
{
public T Data;
}
Scroll事件监听器:
imagegrid.ScrollStateChanged += (o, e) =>
{
if (e.ScrollState != ScrollState.Idle)
{
imageAdapter.IsScrolling = true;
}
else
{
imageAdapter.IsScrolling = false;
imageAdapter.NotifyDataSetChanged();
}
};
答案 0 :(得分:1)
它在android中的Bitmap
内存有限(大约8M)。因此,如果加载了太多图像,则会抛出OOM异常。
除了使用默认图像暂时替换评论中建议的已卸载图像外,我们还需要缓存位图。
要缓存位图,您可以查看Google Android的官方文档:Use a Disk Cache。