我想實現一個簡單的自定義畫廊,以顯示我的手機使用Xamarin.Android的所有照片。 對於我使用GridView與適配器和Xamarin Android自定義畫廊gridview
MediaStore.Images.Thumbnails.GetThumbnail
創建縮略圖但這種方法對於照片數量較大慢,所以我創建一個任務,以使其異步。同時在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;
}
和滾動事件偵聽器:
imagegrid.ScrollStateChanged += (o, e) =>
{
if (e.ScrollState != ScrollState.Idle)
{
imageAdapter.IsScrolling = true;
}
else
{
imageAdapter.IsScrolling = false;
imageAdapter.NotifyDataSetChanged();
}
};
您可以嘗試爲您的'GridView'使用滾動偵聽器,在用戶滾動用戶界面期間加載數據時,經常會出現OOM錯誤。嘗試在用戶界面穩定時加載數據,並且如果此時未加載縮略圖,請使用默認值暫時替換它。 –
我試圖添加OnScrollListenerStateChanged只滾動縮略圖時,滾動未處於活動狀態(穩定)。此外,我還添加默認的位圖,當圖像尚未加載。最後在OnScrollListenerStateChanged中創建一個NotifyDataSetChanged()來更新UI。 (在第一篇文章中添加了編輯更改) – TGuerin