Lazy Loading Images in a ListView

by Samuh » Tue, 08 Dec 2009 22:34:13 GMT

Sponsored Links
  trying a hand at ListViews and my current experiment is aimed at
displaying some data in a ListView. The data to be displayed in each
row is simple: an image and some text. The images come from a remote
server and the textual data is hardcoded.

I have a class that downloads images using AsyncTask and caches the
list of images fetched as SoftReferences in a LinkedHashMap. I am also
passing a reference of the view to this class, so when the image
download/cache read is complete the class will set appropriate Bitmap
in the view.

Following is my code:

//class BasicAdapter extends ArrayAdapter<RowData>
static class ViewHolder{
TextView text;
ImageView icon;

public View getView(int position, View convertView, ViewGroup parent)
ViewHolder holder;
if(convertView == null){
convertView =

holder = new ViewHolder();
holder.text = (TextView)
holder.icon = (ImageView)

holder = (ViewHolder) convertView.getTag();


//set default icon

// set the actual image from the cache
String imageUrl = mDataSet.get(position).getMUrl();
WriteThroughCache.getImage(holder.icon, imageUrl);

return convertView;


// My helper class that manages cache and image Download

public class WriteThroughCache{
static LinkedHashMap<String,SoftReference<Bitmap>> imageCache =
new LinkedHashMap<String,SoftReference<Bitmap>>();

public static void getImage(ImageView icon, String imageUrl){
Bitmap image = imageCache.get(imageUrl).get();
if(image != null){

new LoadImageInBackground().execute(new


static class LoadImageInBackground extends AsyncTask<Object, Void,
ImageView mIcon = null;
String mUrl = null;
protected Bitmap doInBackground(Object... params) {
mIcon = (ImageView)params[0];
mUrl = (String) params[1];
Bitmap image = BitmapFactory.decodeStream
return image;
protected void onPostExecute(Bitmap result) {
imageCache.put(mUrl, new SoftReference<Bitmap>(result));


Problem: The applicatio

Lazy Loading Images in a ListView

by skyhigh » Wed, 09 Dec 2009 15:46:01 GMT

 I haven't tried to do a lazy background image load like you are doing,
but have done some code that uses a holder/wrapper to store the layout
findViewById which is a nice optimization so that it doesn't have to
call inflate and findViewById again when each row is displayed.  My
understanding is that when you do this it will allocate enough views
for each of the rows that are visible on the screen, and then as a row
scrolls off the screen, it will reuse the already initialized view for
a new row that is scrolling onto the screen.

In looking at your code I think you may have a problem because of the
way that the views for each row get reused when they disappear from
sight.  The same view that was used for a row that just disappeared
can be reused for a new row that is appearing as the list scrolls.
Your getView routine is handling this by detecting that the
convertView is non-null when it has already been filled in when this
view was used by a previous row.  However you don't have any mechanism
to detect when a view has been reused and is now displaying a
different row and the URL has changed to a different URL while the
background AsyncTask was retrieving the image.  By the time the
AsyncTask finishes retrieving the image, the view that it saved the
reference to, in order to set the image, could have been reused to
display a different row in the list.  If you can add code to check if
it is still the expected URL prior to setting the image I think it
might solve your problem.  If the URL has changed then skip setting
the lazy image on that view, and just add the image to your cache.


Sponsored Links

Lazy Loading Images in a ListView

by Romain Guy » Wed, 09 Dec 2009 16:08:00 GMT

 You can check out the example I wrote at It
does lazy loading of images from the sdcard.


Lazy Loading Images in a ListView

by Samuh » Thu, 10 Dec 2009 22:20:01 GMT

 skyhigh: thanks for your reply!

As you can see, I have used a view holder pattern too; as was
explained in the Google I/O conference by Romain.

Thanks for pointing this out; I was able to recreate the situation
that you've described by inserting a delay in the doInBackground()
method of AsyncTask. Result: When I scrolled a few dozen rows and
stopped, the icons in the new Frame displayed the older icons first
and then the list was refreshed.

I could probably work around this by:
1. Tag the view with some unique Id and when setting the image in the
AsyncTask, find the View by Tag, and then proceed with setImage(..).
2. I think, I could optimize the implementation further by not loading
the image when the list is scrolling; similar to what SlowAdapter does.


Lazy Loading Images in a ListView

by Samuh » Thu, 10 Dec 2009 22:21:28 GMT


Thanks Romain for your time; I will surely check the implementation



Lazy Loading Images in a ListView

by Lee » Fri, 11 Dec 2009 02:48:03 GMT

 I have also recently been implementing adapter-based image loading
into a list.

I found that when I used SoftReferences, they started getting cleared
very quickly indeed, after my cache of thumbnails was up to maybe 20
or so.

When I use normal references, the cache grows happily to a couple of
hundred thumbnails without OOMs being thrown.

Being a java newbie, I don't pretend to understand this, but I went
with normal references and careful OOM catching.

BTW, tip maybe, I used onScroll and onScrollStateChanged from the list
to initiate cache fills (rather than filling as a result of calls from
getView()) because otherwise I found scrolling getting sluggish as the
image cache got busy
filling the cache while scrolling was still ongoing.



Lazy Loading Images in a ListView

by Lee » Fri, 11 Dec 2009 02:49:12 GMT

 Oh nevermind, I saw you realised the scroll problem already :-)



Lazy Loading Images in a ListView

by Samuh » Fri, 11 Dec 2009 11:40:34 GMT

 > I found that when I used SoftReferences, they started getting cleared

One of the possible reasons, I can think of, why Romain chose to
persist the fetched images on SDcard(in his Shelves app) is because
when caching is done on heap, the objects keep getting garbage
collected so you have to repeat the time consuming fetches.


Lazy Loading Images in a ListView

by Sam Dutton » Fri, 15 Jan 2010 06:23:51 GMT

  haven't read through the whole thread, but FWIW there's a very good
introduction to list view 'lazy loading' techniques in Beginning

Look in the sample code under fancylists -- well documented in the

Sam Dutton

On Dec 8 2009, 2:34pm, Samuh <> wrote:
> Thanks.

Lazy Loading Images in a ListView

by Mark Murphy » Fri, 15 Jan 2010 06:38:11 GMT



I wrote that book, and I'm pretty sure I didn't cover the OP's question

It's related to the Fancy ListViews chapter, but adding asynchronous
thumbnail loading is a whole 'nuther kettle of fish.

Fortunately for the OP, I have already filleted, breaded, and seasoned
that kettle of fish. Here's a reusable component that offers
asynchronous thumbnail downloading and application to a ListView: 

Mark Murphy (a Commons Guy)  | 

_The Busy Coder's Guide to *Advanced* Android Development_
Version 1.3 Available!

Other Threads

1. Animated window transitions in Android 1.5

You generally don't -- let the system use its standard one.

Dianne Hackborn
Android framework engineer

Note: please don't send private questions to me, as I don't have time to
provide private support, and so won't reply to such e-mails.  All such
questions should be posted on public forums, where I and others can see and
answer them.


2. is it possible to save an mp3 from my applications raw folder onto the sdcard?

My application stores mp3 files in the raw folder. Is it possible to
save an mp3 from that location to the sd card?

3. LooperThread

4. Is referencing resources across resource files dependent on the filename?

5. How do I pass data between applications?

6. Ability to quit/disable an app after trial period?

7. Why did Google Groups not post my comments?