Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy-loading images in ListView on Android

I implemented the lazy-loading images in my ListView. I use a AsyncTask to download the image from the internet and bind it to the ImageView in the UIThread.

It's working except that when I scroll the ListView vary fast, the downloaded images sometimes are binded into the wrong items in the list.

I guess the problem is from the reuse of convertView in the BaseAdapter. Any ideas to solve it?

Many thanks.

EDIT: I post the answer as following:

public void setBitmap(int position, Bitmap image) {
    View itemView = mListView.getChildAt(position - mListView.getFirstVisiblePosition());
    if (itemView != null) {
        ImageView itemImageView = (ImageView) itemView.findViewById(R.id.item_imageview);
        itemImageView.setImageBitmap(image);
    }
}
like image 960
shiami Avatar asked Sep 22 '10 06:09

shiami


People also ask

How to lazy load images in Java?

Next, to lazy load a simple img element, all you need to do in your markup is: <img class="lazy" src="placeholder. jpg" data-src="image-to-lazy-load. jpg" alt="Alternative text to describe image.">


2 Answers

There are two problems that will arise during lazy loading of images in a ListView.

  1. The old images are still shown until the new ones are loaded. This is easy just set the ImageView to an image is loading view or set it to invisible before starting the image download.
  2. The second problem is harder to solve. Imagine you are scrolling very fast through your list. Now your views may be recycled before the old AsyncTask has finished loading the image. You now have two tasks running that in the onPostExecute method will set an image to the imageview. Now for a short time the wrong image will be shown until the second Task finishes, or even worse for some network related reason they don't finish in the order they started and you have the wrong image overwrite the correct image. To solve this you have to check what image should be displayed after the task finished. In the View class are two methods for things exact like this one:

    setTag and getTag You can bind any object to the imageview that comes into your mind. In most of the cases I use setTag to bind the URL of the image as a String to the imageview before I start a task. Now I can cast getTag to a String after the task finished and compare the URL that should be displayed with the URL that I downloaded and only set the image if necessary.

like image 144
Janusz Avatar answered Oct 09 '22 18:10

Janusz


Create a function called void setBitmap(Bitmap bitmap, int position) or similar in your adapter. Let your AsyncTask call this method when a new bitmap is available. This method may then call notifyDataSetChanged() on the UI-Thread itself to ensure the views get refreshed. Holding references to views in an adapter (even by holding them in an AsyncTask) is dangerous!

like image 44
mreichelt Avatar answered Oct 09 '22 16:10

mreichelt