Xamarin Android自定义画廊gridview

时间:2017-07-02 11:07:25

标签: c# android gridview xamarin xamarin.android

我正在尝试使用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();
            }
        };

1 个答案:

答案 0 :(得分:1)

它在android中的Bitmap内存有限(大约8M)。因此,如果加载了太多图像,则会抛出OOM异常。

除了使用默认图像暂时替换评论中建议的已卸载图像外,我们还需要缓存位图。

要缓存位图,您可以查看Google Android的官方文档:Use a Disk Cache