Search code examples
androidandroid-2.1-eclair

setImageBitmap in BaseAdapter#getView doesn't update ImageView


I have an app that downloads a bunch of images in a background thread. As each icon gets downloaded, I add it to an ArrayList in my custom Adapter which subclasses BaseAdapter. Each row in the ListView that uses the BaseAdapter has an ImageView. In getView, I do the following.

public View getView(int position, View convertView, ViewGroup parent) {
    final MyCustomImageClass imageObject = data.get(position);
    View vi = convertView;

    if(convertView==null) {
        vi = inflater.inflate(R.layout.list_row, null);
    }

    ImageView thumbnail = (ImageView)vi.findViewById(R.id.list_image);
    File appDir = new File(Utils.getAppFilesDir() +"");
    File imageFolder = new File(appDir, imageObject.getImageFolderName());
    File imageDir = new File(imageFolder, imageObject.getIconFilename());
    Log.e("myapp", "row image dir: " + imageDir.toString());
    if(imageDir.exists()) {
        Bitmap imageBitmap = BitmapFactory.decodeFile(imageDir.toString());
        thumbnail.setImageBitmap(imageBitmap);
    }
    thumbnail.invalidate();
}

But what I'm seeing is that thumbnail is re-using old images. Like, the first few rows will have the same thumbnail image even though I see a different path for them in logcat.

How do I tell the row in a ListView that its ImageView has a new Bitmap image?


Solution

  • Each row in the ListView will get recycled, so as one goes off screen, the next one coming on will reuse that container. You are probably not satisfying the if statement on the new updated ImageView so that image is not set to what you want, so it just reuses the old one. Make sure your imageDir.exists() will complete successfully to ensure the new view will update correctly. Also, I don't think there is any reason to call invalidate.

    Edit: I see why you are calling invalidate() now, but it is still not necessary. I would suggest using a default image for the ImageView, like the android supplied one, then do something like this:

    if(imageBitmap != null)
      thumbnail.setImageBitmap(imageBitmap);
    else
      thumbnail.setImageDrawable(R.drawable.content_picture);
    

    where R.drawable.content_picture is the default "no picture to show" image and is also the one defined for the ImageView in the XML file.

    Lastly, you should look into using a ViewHolder to speed up the rendering of the ListView. Here is an example: How to implement a view holder?

    If anything I've said here does not make sense, just ask for clarification.