Ich versuche, eine einfache benutzerdefinierte Galerie zu implementieren, um alle Fotos von meinem Telefon mit Xamarin.Android anzuzeigen. Dafür verwende ich eine Gridview mit einem Adapter und Thumbnails mitXamarin Android benutzerdefinierte Galerie Gridview
MediaStore.Images.Thumbnails.GetThumbnail
Aber diese Methode für eine große Menge von Fotos langsam ist, also habe ich erstellen eine Aufgabe, um es asynchron zu machen. Fügen Sie auch CanceltionToken in der GetView-Methode hinzu, um mehrere gleiche Aufgaben gleichzeitig abzubrechen.
Aber etwas schief geht und meine app stürzt ohne Nachrichten oder manchmal "outofmemory exceception".
EDITED CODE
Hier mein Adapter:
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);
}
}
}
Die GetImageThumbnailAsync ruft Miniatur aus der GetView Position.
Und nun die ViewHolder Klasse:
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;
}
Und der Scroll-Ereignis-Listener:
imagegrid.ScrollStateChanged += (o, e) =>
{
if (e.ScrollState != ScrollState.Idle)
{
imageAdapter.IsScrolling = true;
}
else
{
imageAdapter.IsScrolling = false;
imageAdapter.NotifyDataSetChanged();
}
};
Sie können versuchen, einen Scroll-Listener für Ihre 'GridView' zu verwenden, es ist oft ein OOM-Fehler beim Laden von Daten während Benutzer die Benutzeroberfläche scrollen. Versuchen Sie, Daten zu laden, wenn die Benutzeroberfläche stabil ist und wenn das Thumbnail zu diesem Zeitpunkt nicht geladen ist, verwenden Sie einen Standard, um es vorübergehend zu ersetzen. –
Ich habe versucht, OnScrollListenerStateChanged hinzuzufügen, um nur Thumbnails zu erhalten, wenn der Bildlauf nicht aktiv ist (stabil). Außerdem füge ich Standard-Bitmap hinzu, wenn das Bild noch nicht geladen ist. Und schließlich eine NotifyDataSetChanged() in der OnScrollListenerStateChanged, um die Benutzeroberfläche zu aktualisieren. (Editieränderung im ersten Post hinzugefügt) – TGuerin