Using an adapter with asynchronous task - android

I have a class that extends BaseAdapter, which I use for a ListView. In the getView() method of that class I'm using an AsyncTask with a callback method to download an image (once downloaded, I store it, so I don't have to download it again). When the ListView loads the items first, only the first item displays an image an then starts to change the images (repeatedly displaying the images of the other items). Later also the other items start showing the same behaviour. After a while they stop cycling the images and each item shows the correct images. If I scroll the ListView the items are starting again to cycle the images.
This only happens, if I recycle the convertView parameter, that is passed to getView(). If I don't the images take very long to show up, and I'm afraid I'm creating too much new Views.
Thanks in advance for any advices, to get this working properly.

The simple way to get this going is to dump all your own image loading code and use something that already handles this, like Square's Picasso. There are plenty of alternatives if you do not like Picasso.
Otherwise, your tasks will need to be aware of the recycling, so they do not attempt to update an ImageView that now needs a different image. For example, you could use setTag() and getTag() on the ImageView to store (and retrieve) the URL the ImageView currently needs, and if the image downloaded by the task is some other URL, don't apply it.
But, again, please use an existing library for this. It's 2013: few people should be rolling their own download-the-images-for-use-in-ListView-rows code anymore.

Related

Is it normal to use AsynTask in viewHolder in CustomAdapter

I have custom adapter (one image, 2 text fields), and I need to check image inside viewHolder. When image is already exist, show that image in ImageView and when image isn't exist, I need to check connection, if all good, show progressbar, download image, and show it, and if all bad then show default image. Sorry for my English.
No you should not implement a Async Task inside ViewHolder bcoz you do not know how much time it will take to load images and the user will be pissed at waiting for the listview to come up.
There are lot of tutorials out there you should use lazy loading for images if you are using URLS for images if there are not much images then you can store it in database or in a file and show any time in the listview
Hope it Helps :)
I've seen many people using, it is normal for small operations.
but it can't be used for tasks which take time - as the user experience is affected by lagging.
for small operations you can use it.

ListView with Image Adapter Locking the UI Thread

I have a listview that load images with a adapter. Every time that I scroll the screen, the listview calls the getView to refresh the listview, then the getView loads a image, doing that in my ui thread, locking my screen for a moment.
What I did was to load the images in a AsyncTask class. But the problem is that it take a little bit, and when you scroll you see the wrong image, after a while it louds the right image. I didn't want to have that problem, showing the wrong image for a moment.
I search and saw that there is no way to stop that listview automatic refresh.
What should I do to resolve that problem? Any tutorial would be helpful.
What should I do to resolve that problem?
Set the ImageView to show a placeholder image in getView(), while you fork the task to load the real image. Or, as others have suggested, use any number of libraries for managing all of that for you (and I echo the Picasso recommendation).

Download images in async task and show them in ListView

I've a list of URLs, each corresponding to an image.
I need to display these images in a ListView.
Currently, my approach is pass this List<String> containing URLs to a CustomAdapter (extending BaseAdapater).
Each row item in the ListView will be inflated with an ImageView.
Then in the getView() method, if currentImageView == null, then I'll start an AsyncTask, which will download the bitmap for that imageList.get(position).
Then in the postExecute(), I'll set currentImageView.setBitmap(downloadedBitmap).
In this manner,from inside the adapter, I'll call AsyncTask one-by-one for each image.
If you think, there is something wrong in this approach then please let me know. Also, please suggest the correct approach.
One pitfall with approach I've found in when AsyncTask for a certain list element is in progress & user scrolls down then back up, the same async task will be called again.
How can I prevent this?
When your views get recycled, the currentImageView will not be null and it will keep displaying the same images. I would suggest using Universal Image Loader. It takes care of all of that for you, with TONS of extra features like caching and what not.
Try this library
Then in getView method, simply add this code
UrlImageViewHelper.setUrlDrawable(holder.image, model.getimageURL(), R.drawable.placeholder);
parameter one is your ImageView, second parameter is Image URL, and the last is placeholder image.

A problem using ListView

Hi geeks!
Here is a problem using ListView.
When generating a single list item view, in the method of BaseAdapter.getView, some continuous async remote data request may be issued, like getting the photo of a person.
But when the response is back, the list item view might be reused, as the mechanism of ListView works. I cannot find the right view to put the response to.
How did you guys fix this problem?
As you say, there is a good chance that by the time you've loaded the image that the list item is no longer visible or even existing. So you can check what is on screen using ListView.getFirstVisiblePosition() and ListView.getLastVisiblePosition(), if it is onScreen get the item and set the image. Otherwise you have to cache the image (either memory or sd-card depending on how many images and the size of them) and next time getView() is called for that item just use the cached image.
I hope that helps.
I believe what your after is "lazy image loading" + caching. I got my implementation going via this answer. The package is called LazyList.
I hope this helps

What are the ways to get a handle on the view amidst recycling?

I have a GridView, in my activity, that displays about 30 thumbnails fetched from a remote server. I am doing 2-level caching for the images:
there is an in-memory cache(HashMap using softReferences)
Secondly, all the images fetched are written to Sdcard(so as to avoid refetches when in-memory bitmaps are GC'd).
From the getView of the GridView-Adapter, I call getCachedImage function of the Cache class, which will either return a default image or an image from one of the caches. When a default image is returned, the Cache class starts a AsyncTask to fetch the image from the remote server. This image is then also written to both the caches.
The problem is: When the AsyncTask finishes, I want it to also update the UI alongwith the caches. I tried passing the instance of the GridView child(ImageView) to the AsyncTask and then setting the image of this child view, in the postExecute of the AsyncTask but due to View recycling, this approach results in incorrect images in incorrect views, if the fetches take long time.
What are the ways in which i can make my AsyncTask more proactive meaning it should let the UI know that image download has finished?
Thanks!
The approach I took with CWAC-Thumbnail is to do everything you did, but also stick the URL presently being displayed by an ImageView in that ImageView object's tag via setTag(). Then, when the AsyncTask ends, I check the tag to see if the URL of the ImageView matches the URL the task downloaded. If they do, I apply the image. If not, I don't.
A way to handle this case is to simply write a Custom Image View (which inherits of ImageView) that is able to deal with all this stuff by itself.
Then you can just put your Custom image Views wherever you need it and just call something like "startLoading" on it.
In this "startLoading", just put the logic you described.

Categories

Resources