1

I am using a recyclerView to show images using asysnc task. I am getting the images from a web server. My code is

from onBindViewHolder methode I call

new ImageLoadTask(url, holder.imageView).execute();

My ImageLoader asysnc task is

public class ImageLoadTask extends AsyncTask<Void, Void, Bitmap> {

        private String url;
        private ImageView imageView;
        ProgressDialog pDialog;

        public ImageLoadTask(String url, ImageView imageView) {
            this.url = url;
            this.imageView = imageView;
        }

        @Override
        protected Bitmap doInBackground(Void... params) {
            try {
                URL urlConnection = new URL(url);
                HttpURLConnection connection = (HttpURLConnection) urlConnection
                        .openConnection();
                connection.setDoInput(true);
                connection.connect();

                InputStream input = connection.getInputStream();
                Bitmap myBitmap = BitmapFactory.decodeStream(input);
                return myBitmap;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            super.onPostExecute(result);
            imageView.setImageBitmap(result);
        }
    }

The problem is when I scroll and skip one or more views before the image is downloaded and that view is recycled the image donwnload reqest is not canceled on those intermediate view resulting in a flash of that/those image(s) before the actual image is loaded in that view.

I tried passing the HttpURLConnection from the adapter and checking if its not null and then calling disconnect on this as shown before from onBindViewHolder methode, but still it happens. I am using the

if (holder.urlConnection != null)
    {
        holder.urlConnection.disconnect();
        try {
            holder.urlConnection.getInputStream().close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        holder.urlConnection = null;
    }

    new ImageLoadTask(url, holder.imageView,holder.viewHolderActivity, holder.urlConnection).execute();

What can I do to cancel the image requests ?

Kathi
  • 1,061
  • 1
  • 16
  • 31
Pankaj Bansal
  • 889
  • 1
  • 12
  • 37

4 Answers4

5

Save ImageLoadTask link in holder

    if (holder.urlConnection != null)
        {
            holder.urlConnection.disconnect();
            try {
                holder.urlConnection.getInputStream().close();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            holder.urlConnection = null;
        }

      holder.imageTask = new ImageLoadTask(url, holder.imageView,holder.viewHolderActivity, holder.urlConnection);
      holder.imageTask.execute();

and cancel it on

//Called when a view created by this adapter has been recycled.
public void onViewRecycled(VH holder){
      holder.imageTask.cancel();
}
Marlen
  • 146
  • 8
1

On your ViewHolder keep a reference to your ImageLoadTask. in the onBindViewHolder method cancel the existing ImageLoadTask by calling its cancel method and create a new task for the new image. Note that when a AsyncTask is cancelled it will not call the onPostExecute method instead it will call onCancelled.

dishan
  • 1,346
  • 12
  • 21
0

Try to cancel asynctask using cancel() method in order to cancel the image request:

ImageLoadTask imageLoadTask=new ImageLoadTask(url, holder.imageView);
imageLoadTask.cancel(true);
Dhaval Shah
  • 618
  • 6
  • 15
0

Use glide: https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en

It's a fast and responsive framework for loading images from any given back-end. You can do stuff like setTimeout, cancelRequests, fadeEffects and some other stuff. You don't even have to worry about how to handle the network request. Glide will simply do that for you.

Usage:

Glide.with(context)
  .load(imageLoadPath)
  .placeholder(imgToShowWhileLoading)
  .centerCrop()
  .into(imageView);

And then you can set the GlideModule configuration like this: (Original code snippet: glide image loading timeout increase). Make a custom class to implement GlideModule. In one of it's overriding methods:

@Override
public void registerComponents(Context context, Glide glide) {
    final int retryPolicy = 10000;
    RequestQueue queue = new RequestQueue(
            new DiskBasedCache(new File(context.getCacheDir(), "volley")),
            new BasicNetwork(new HurlStack())) {
        @Override public <T> Request<T> add(Request<T> request) {
            request.setRetryPolicy(new DefaultRetryPolicy(retryPolicy, 1, 1);
            return super.add(request);
        }
    };
    queue.start();
    glide.register(GlideUrl.class, InputStream.class, new VolleyUrlLoader.Factory(queue));
}

Play with timeout limit all you want, and see how it can meet your needs.

Community
  • 1
  • 1
AnkitNeo
  • 122
  • 1
  • 11