androidimageviewbitmapfactoryrecyclerview-layoutskia

ImageView RecyclerView Lazy Load


I have a RecyclerViewAdapter which in onBindViewHolder, I make an AsyncTask call to download the image required from Google Cloud Storage.

There are some items in the RecyclerViewAdapter which call for the same image. I tried to deal with this by only downloading the image if it doesn't already exist in the local file storage; otherwise if it does then it uses the image that has already been downloaded.

Now what's happening is, if there are multiple items from the RecyclerView calling for the same image at near enough the same time, one of the items ImageView will just be blank/white but the rest of them will display the image correctly.

I was hoping to be able to capture this scenario and just use Thread.sleep and then try to get/use the file again but I'm not getting any exceptions thrown or anything so I'm not sure how to even capture that scenario to deal with it.

The only thing that I can see in the logcat which looks remotely helpful is the below:

D/skia: --- Failed to create image decoder with message 'unimplemented'

However it's not throwing an exception, it's just logging it as a message.

It does however point to there being an issue with the decoding of the image. So I checked the BitmapFactory.decodeFile documentation and it says that it returns a null if it couldn't decode it. So I tried to check if my bitmap was null after trying to decode but it never hit that IF statement meaning it was never returning null so I'm not sure what to do.

new Getlogos(holder.logoImageView.getTag().toString(), holder.itemView.getContext(), new Getlogos.AsyncResponse() {
    @Override
    public void returnBitmapURI(String URI, String tag) {
        if (holder.logoImageView != null && holder.logoImageView.getTag().toString().equals(tag)) {
            if (URI.contains("drawable://")) {
                int id = Integer.parseInt(URI.substring(11));
                Bitmap myBitmap = BitmapFactory.decodeResource(context.getResources(), id);
                holder.logoImageView.setImageBitmap(myBitmap);
            } else {
                Bitmap myBitmap = BitmapFactory.decodeFile(URI);
                holder.logoImageView.setImageBitmap(myBitmap);
            }
        }
    }
}).execute();

The issue only occurs sometimes and it doesn't happen to the same image consistently. it normally varies between some of the items that have the same image to download/use. Sometimes it doesn't occur at all.

Can anyone shed any light on where that skia message is coming from and how I can capture it when it fails to decode, so I can handle it?


Solution

  • Use Glide to display image in recyclerView

    Add this dependencies to build.gradle

    implementation 'com.github.bumptech.glide:glide:4.8.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
    

    Inside onBindViewHolder

    Request option to show error image, placeholder image etc. CircularProgressDrawable for placeholder drawable(optional)

    val circularProgressDrawable = CircularProgressDrawable(mContext)
            circularProgressDrawable.strokeWidth = 5f
            circularProgressDrawable.centerRadius = 30f
            circularProgressDrawable.start()
    
            val requestOption : RequestOptions = RequestOptions()
                    .placeholder(circularProgressDrawable)
                    .error(R.drawable.ic_error_1)
                    .diskCacheStrategy(DiskCacheStrategy.ALL)
                    .priority(Priority.HIGH)
                    .dontAnimate()
                    .dontTransform()
    

    initialize Glide as shown below

    Glide.with(mContext)
                .load(model.imageUrl)
                .apply(requestOption)
                .into(holder.imageView!!)