Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ListView asynchronous image loading strategy

I currently have a ListView with a custom adapter that gets information describing the content of the rows asynchronously. Part of each row is an image URL, that I'm planning to download asynchronously and then display.

My current plan for a strategy to download these images is:

  • Keep a cache of soft references to downloaded Bitmap objects.
  • When a getView() is called and the bitmap is in the cache, set the bitmap for the ImageView directly.
  • If the bitmap isn't in the cache, start loading it in a separate thread, after the download is complete add it to the cache and call notifyDataSetChanged() on the adapter.

I am also planning to kill pending downloads when the Activity object owning the ListView's onDestroy()-method (Or possibly even in the onPause()-method) is called, but most importantly I want to kill the download of pending images when the row goes off screen. I might only actually cancel the download after a short delay, so it can be resumed without wasting bandwidth if the row comes on-screen quickly again.

I, however, am unsure about a few things:

  • What is the best way to detect when a row goes off-screen so I can cancel the download?
  • Is calling notifyDataSetChanged() the best thing to do after the download has completed or is there a better way?

Also any comments on the whole strategy would be appreciated.

like image 973
JPvdMerwe Avatar asked Jun 26 '11 18:06

JPvdMerwe


2 Answers

I don't think calling notifyDataSetChanged() is really needed... I would do it like that:

  • store URL as Tag in the view when created/updated
  • register a listener in downloader thread (async task???) for download keeping reference to the view and the URL
  • whenever image is downloaded asynchronously, I check TAG in the view and if it matches - i would update the ImageView (important to do it in UI thread, but when using async task, it is given). The image should also be stored on SD card (and every time you request URL you should check if it is not already downloaded).
  • every time when getView() reuses the view (passed view is not empty) I would check the Tag (old URL), replace it with the new URL and cancel the download of the oldURL.

I think it would be pretty much it (some corner cases might happen)...

like image 183
Jarek Potiuk Avatar answered Oct 05 '22 00:10

Jarek Potiuk


I use the getFirstVisible and getLastVisible AdapterView properties to detect the visible rows, and put requests in a fixed size stack.

My project is open source and has a most permissive license, if you want to use it: https://github.com/tbiehn/Android-Adapter-Image-Loader

-Travis

like image 42
Travis Biehn Avatar answered Oct 04 '22 23:10

Travis Biehn