Aha! I think I may know the issue. Right now, your getView
method sets your ImageView
like this:
- Gets movie object at position
- Pulls out the movie's thumbnail url
- Using that url, it tries to find the image in the cache
- If it finds the image, it sets it
- If it can't find the image, it starts an async network request to go get it, and sets it after it gets downloaded.
Your issus arises since ListView
reuses its rows' View
s. When the first View
scrolls off the screen, rather than inflate a new one, ListView
passes the now offscreen row's View
in as convertView
for you to reuse (this is for efficiency).
When your getView
gets a convertView
that is getting reused, its ImageView
has already been set from the row that had it before, so you see the old image from the offscreen row's View
. With your current getView
process, you check for the new row's image, and it doesn't find it in the cache, it starts a request to download it. While it is downloading, you see the old image until you get the new image.
To fix this, you need to make sure you set every field in the row's View
immediately, to make sure you don't have any View
s showing stale data. I would suggest you set the ImageView
to the default drawable
resource (you have set in your R.layout.movie_data_row
) while you wait for the network download to get the image.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.movie_data_row, null);
}
ParkCinema movie = movieDataItems.get(position);
ImageView imageView = (ImageView) convertView.findViewById(R.id.movie_thumb_icon);
if (movie != null) {
String url = movie.poster();
if (url != null) {
Bitmap bitmap = fetchBitmapFromCache(url);
if (bitmap == null) {
// Set the movie thumbnail to the default icon while we load
// the real image
imageView.setImageResource(R.drawable.movie_thumb_icon);
new BitmapDownloaderTask(imageView).execute(url);
}
else {
// Set the image to the bitmap we get from the cache
imageView.setImageBitmap(bitmap);
}
}
else {
// Set the movie thumbnail to the default icon, since it doesn't
// have a thumbnail URL
imageView.setImageResource(R.drawable.movie_thumb_icon);
}
}
else {
// Set the movie thumbnail to the default icon, since there's no
// movie data for this row
imageView.setImageResource(R.drawable.movie_thumb_icon);
}
-Edit-
Updated to be even more robust, using your drawable
. You also have an issue with your BitmapDownloaderTask
, it does not handle errors/null. Try adding this as well.
@Override
protected void onPostExecute(Bitmap bitmap) {
addBitmapToCache(url, bitmap);
if (bitmap == null) {
// Set the movie thumbnail to the default icon, since an error occurred while downloading
imageViewReference.get().setImageResource(R.drawable.movie_thumb_icon);
}
else {
imageViewReference.get().setImageBitmap(bitmap);
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…