Fedor
Fedor

Reputation: 83

Best way to stop all threads that are loading image into ImageView in RecyclerView adapter after data changed

Hi i have my adapter for RecyclerView and i need to show a large list (different lists with images). All images i am loading into ImageView from a separate thread. Each thread for each ImageView. The problem is in that when i am changing data for my adapter and calling notifyDataSetChanged(); - sometimes the new ImageViews are displaying images from a previous data set. I understand that this is happening because of RecyclerView is reusing the ViewHolder item - in which the old thread is still downloading the old image, not new. So i am wondering how can i stop all threads when my dataset in adapter is changing. May be the approach is to put all threads into an array and stop all of them before calling notifyDataSetChanged();? But i think there are can be more elegant solutions? This is my code:

@Override
public void onBindViewHolder(ItemHolder holder, int position) {
            ........
            holder.itemIcon.setImageResource(tree.getDefaultCover());

            BitmapWorkerTask bitmapWorkerTask = new BitmapWorkerTask(holder.itemIcon, tree);
            bitmapWorkerTask.execute(file);
            ......
}

then in my Worker task i am setting Bitmap in postExecute method

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

Upvotes: 0

Views: 375

Answers (4)

Dibzmania
Dibzmania

Reputation: 1994

Android Dev site has addressed the exact problem for working with images in a list UI. Basically the idea is to define a wrapper over the drawable which keeps a reference to the task which is supposed to load the image for it. Since views are recycled in a list UI, a particular view might get recycled even before the task to load the image for it could be executed. This pattern helps to preempt this and cancel the task.

https://developer.android.com/training/displaying-bitmaps/process-bitmap.html#concurrency

Upvotes: 1

k3b
k3b

Reputation: 14755

With AsycTask.execute only one task/thread is actve at a time. the next is started when the previous finishes. in your task you have to check isCanceled() at least in the beginning of doInBackground and in the beginning of onPostExecute.

If holder knows taks and task knows holder you can ask each holder to stop it-s task (call the cancle method).

since you have a cyclic reference between holder and task there is a risk for memory leaks.

you must make shure that the holder forgets it-s task once it is cancleded/finished or there is a configuration change (i.e. screen rotation).

I have done this in APhotoManager. It contains a GalleryCursorFragment with the gridview and a GalleryCursorFragment with an embedded GridCellViewHolder

Upvotes: 1

android_jain
android_jain

Reputation: 798

you can stop do in asyncktack to get new image in recycler view use this code for stoping asncktack if (asyncktask != null){ asyncktask .cancel(true);} then call notifyDataSetChanged();

Upvotes: 0

Andrej Jurkin
Andrej Jurkin

Reputation: 2256

No need to reinvent a wheel here. Just use Glide.

Glide.with(this).load("img_url").into(imageView);

Done.

Upvotes: 0

Related Questions