Florian Shena
Florian Shena

Reputation: 1434

Android ArrayAdapter loading list view images using universal-image-load library

I am using array adapter to populate a list of places with custom data. The text loads correctly, the problem lies on the image loading. I am using the Universal-image-loader to load images asynchronously. The images are loaded but they are placed in the wrong order on the list and also they just keep reloading over and over again in the wrong place. Here is my adapter code:

public class PlacesListViewAdapter extends ArrayAdapter<PlacesListItem> {

    private final Context context;
    protected ImageLoader imageLoader = ImageLoader.getInstance();

    public PlacesListViewAdapter(Context context, int resourceId, List<PlacesListItem> places) {
        super(context, resourceId, places);
        this.context = context;
    }

    private class ViewHolder {
        ImageView ivPlaceLogo;
        TextView txtPlaceName;
        TextView txtPlaceType;
    }    

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        PlacesListItem placesListItem = getItem(position);
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         if (convertView == null) {
             convertView = inflater.inflate(R.layout.places_list_item, parent, false);
             holder = new ViewHolder();
             holder.txtPlaceName = (TextView) convertView.findViewById(R.id.place_name);
             holder.txtPlaceType = (TextView) convertView.findViewById(R.id.place_type);
             holder.ivPlaceLogo  = (ImageView) convertView.findViewById(R.id.place_logo);
             convertView.setTag(holder);
         } else {
             holder = (ViewHolder) convertView.getTag();         
         }
         holder.txtPlaceName.setText(placesListItem.getPlaceName());
         holder.txtPlaceType.setText(placesListItem.getPlaceType());
         imageLoader.displayImage(placesListItem.getPlaceLogoURL(), holder.ivPlaceLogo);
         return convertView;    
    }
}

Upvotes: 1

Views: 1648

Answers (3)

Florian Shena
Florian Shena

Reputation: 1434

DisplayImageOptions options = new DisplayImageOptions.Builder()
                                     .showImageOnLoading(R.drawable.placeholder)
                                     .cacheInMemory(true)
                                     .cacheOnDisc(true)
                                     .considerExifParams(true)
                                     .displayer(new RoundedBitmapDisplayer(5))
                                     .build();

Upvotes: 1

Florian Shena
Florian Shena

Reputation: 1434

I found a solution. The image misplacement on the list was due to the way ImageLoader library handles image loading. I solved the problem by implementing the ImageLoader cache and adding a placeholder for the images that aren't yet loaded.

Upvotes: 0

Stan
Stan

Reputation: 8768

I think your problem is due to the fact that ImageLoader works asynchronously. What happens here is that you store an ImageView instance in the holder, and wait until an image is loaded. But if the list item is reused before the image is loaded, the ImageView is assigned to another position - not the previous one which it corresponded to when you initiated loading.

I don't know which exactly implementation you have tried without the holder, but the current variant does not address asynchrony in any way. The holder just adds another level of reference to the same elements (TextViews, ImageViews) which become invalidated when a list item is reused.

I'd suggest to use the following simple implementation:

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    PlacesListItem placesListItem = getItem(position);

    if(convertView == null)
    {
        LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.places_list_item, parent, false);
    }

    (TextView)convertView.findViewById(R.id.place_name).setText(placesListItem.getPlaceName());
    (TextView)convertView.findViewById(R.id.place_type).setText(placesListItem.getPlaceType());
    imageLoader.displayImage(placesListItem.getPlaceLogoURL(), (ImageView)convertView.findViewById(R.id.place_logo));
    return convertView;    
}

The new code relies on the fact that the ImageLoader provides internal image cache. If it works as I expect you don't need anything else to do. Otherwise, you will notice that every time a list item is reused, new image will replace old one with a lag (possibly unacceptable lag). You should consult with the ImageLoader documentation to enable the cache.

Disclaimer: the code has not been tested, I wrote it out of my head.

Upvotes: 0

Related Questions