Showing Images in list view adapter using Akavache

1k views Asked by At

I am developing a cross platform application using Xamarin. I found Akavache but I couldn't handle image loading using Akavache in listview adapter. It is working really slow. So I need to fix it or find another way to handle this. I couldn't find a good example or sample either.

I am trying to download&load image in Listview Adapter in getView method like this:

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        var view = convertView;
        ViewHolder holder = null;
        if (view != null) // otherwise create a new one
            holder = view.Tag as ViewHolder;

        if (holder == null)
        {
            holder = new ViewHolder();
            view = _activity.LayoutInflater.Inflate(Resource.Layout.Book_Item, null);
            holder.TextItem1 = view.FindViewById<TextView>(Resource.Id.TextItem1);
            holder.TextItem2 = view.FindViewById<TextView>(Resource.Id.TextItem2);
            holder.ImageView = view.FindViewById<ImageView>(Resource.Id.BookImage);
            getImage(position, holder.ImageView, image => holder.ImageView.SetImageDrawable(image.ToNative())); 
        }

        holder.TextItem1.Text = _list[position].volumeInfo.title;
        holder.TextItem2.Text = _list[position].volumeInfo.publishedDate;
        return view;
    }


    public async void getImage(int position, ImageView imageView, Action <IBitmap> setImage)
    {
        var image = await _cache.GetAnImage(_list[position].volumeInfo.imageLinks.smallThumbnail);
        setImage(image);
    }

In my DataCache class I tried getting the image in the following ways, loadImageFromUrl is not working as expected while scrolling, it took much time to reload the images. GetAndFetchLatest and GetOrFetchObject methods are giving InvalidCastException. Exception message is at the end. Do you have any likewise example or any suggestion to fix my problem?

    public async Task<IBitmap> GetAnImage(string imageUrl)
    {
        // return await BlobCache.InMemory.GetAndFetchLatest( imageUrl, async() => await DownloadImage(imageUrl), offset => true);
        // return await BlobCache.InMemory.GetOrFetchObject(imageUrl, async () => await DownloadImage(imageUrl));
        return await DownloadImage(imageUrl);
    }

    public async Task<IBitmap> DownloadImage(string imageUrl)
    {
        return await BlobCache.InMemory.LoadImageFromUrl(imageUrl, true, 100, 100);
    }

UNHANDLED EXCEPTION: 12-11 12:48:54.560 I/MonoDroid( 2017): System.InvalidCastException: Cannot cast from source type to destination type. 12-11 12:48:54.560 I/MonoDroid( 2017): at (wrapper castclass) object:__castclass_with_cache (object,intptr,intptr) 12-11 12:48:54.564 I/MonoDroid( 2017): at Akavache.JsonSerializationMixin+c__AnonStorey11[System.Byte[]].<>m__0 (System.Exception _) [0x00000] in <filename unknown>:0 12-11 12:48:54.564 I/MonoDroid( 2017): at System.Reactive.Linq.ObservableImpl.Catch2+_[System.Byte[],System.Exception].OnError (System.Exception error) [0x00000] in :0 12-11 12:48:54.572 I/MonoDroid( 2017): --- End of stack trace from previous location where exception was thrown --- 12-11 12:48:54.572 I/MonoDroid( 2017): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in :0 12-11 12:48:54.580 I/MonoDroid( 2017): at System.Reactive.PlatformServices.ExceptionServicesImpl.Rethrow (System.Exception exception) [0x00000] in :0 12-11 12:48:54.580 I/MonoDroid( 2017): at System.Reactive.ExceptionHelpers.ThrowIfNotNull (System.Exception exception) [0x00000] in :0 12-11 12:48:54.580 I/MonoDroid( 2017): at System.Reactive.Subjects.AsyncSubject`1[Splat.IBitmap].GetResult () [0x00000] in :0 An unhandled exception occured.

UPDATE: Paul answered me so now I know that I can't use GetOrFetchObject with IBitmaps, because they are UI elements. So exception message is unnecesary now. But loadImageFromUrl method blocks my UI thread while scrolling. So still it is a big problem for me.

1

There are 1 answers

0
Oguz Ozcan On BEST ANSWER

Finally I solved the problem. First of all, I figured out that it is not an Akavache problem by trying a different library (MonoDroid.UrlImageViewHelper) Then I thought that problem could be about listview itself. I am a senior developer so I know listview optimization but still i look for new optimization tactics to see if i missed something.

First of all l recommend you to look at this site: http://leftshift.io/6-ways-to-make-your-lists-scroll-faster-than-the-wind

I already know many of these suggestions but what make the real difference is changing the listview's height to match parent from wrap content. You can try making it 0dp as well. It creates the same result.

Then I found this thread which tells the story behind "match_parent" optimization

Why is 0dp considered a performance enhancement?