Reputation: 5975
As the title says, I'm using a BaseAdapter to display items in a ListView. Obviously a ListView will reuse views, including TextViews and NetworkImageViews.
Assuming 3 items can be displayed at once, the NetworkImageView will be reused for items at index: 1, 4, 7, ....
Depending on what's being displayed, the NetworkImageView will either:
Items 2 and 3 work fine, however in Scenario 1, let's say we're displaying item at index 4 from the network, and the user scrolls to item 7 before 4 is loaded and it's a local resource, we display the local resource. However our network image request may just be finishing now, so we end up displaying an incorrect image.
How can I enforce the proper (expected)behavior?
Upvotes: 1
Views: 1625
Reputation: 6731
You don't need to enforce anything if you use the provided NetworkImageView.
NetworkImageView detects when it has been recycled and cancels the request automatically.
Upvotes: 3
Reputation: 45493
The answer from @Snicolas is spot on, but lacks some pointers on how to actually accomplish that. So here goes.
The general idea is to keep track of the ongoing image requests for every row. That way, when you encounter a recycled row, you can cancel the pending request and kick off a new one for the new data relevant to that row.
One straightforward way to accomplish that is to make the ImageContainer
that you can get back when requesting an image load, part of the adapter's ViewHolder/RowWrapper. If you're not using this pattern yet, you should. Plenty of examples out there, including a good I/O talk.
Once you've added the ImageContainer
to your holder, make an image request and store the container that you get back. Somewhat like this:
ImageListener listener = ImageLoader.getImageListener(holder.imageview, defaultImageResId, errorImageResId);
holder.mImageContainer = ImageLoader.get(url, listener);
The next time a recycled row comes in the adapter's getView()
method, you can get your holder back from it and check wether it has a ImageContainer
set. One of the following 3 scenarios may apply:
ImageContainer
, which means you're good to go to make a new image request.ImageContainer
and the url that it is loading is the same as for the new row data. In this case you don't have to do anything, since it's already loading the image you're after.ImageContainer
but the url that it is loading is different from the new row data. In this case, cancel the request and make a new one for the current row data.If you like, you can move some of this logic by having your BaseAdapter
extension implement AbsListView.RecyclerListener
(and set the adapter as recycler listener for the ListView
or GridView
). The onMovedToScrapHeap(View view)
method gets passed in the view that has just been recycled, which means you can cancel any pending image requests in there.
Upvotes: 5
Reputation: 38168
I don't know this API but my guess is that you should cancel any pending request before recycling such a view. How you can do that I can't say.
Did you here of alternatives like :
Upvotes: -1