1

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;    
    }
}
2
  • Why do you need the holder? Why not to set data directly to textviews and imageview from the current placesListItem? Commented Dec 25, 2013 at 19:26
  • I've tried without the holder too, but the problem remains. Commented Dec 26, 2013 at 12:28

3 Answers 3

1
DisplayImageOptions options = new DisplayImageOptions.Builder()
                                     .showImageOnLoading(R.drawable.placeholder)
                                     .cacheInMemory(true)
                                     .cacheOnDisc(true)
                                     .considerExifParams(true)
                                     .displayer(new RoundedBitmapDisplayer(5))
                                     .build();
Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

0

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.

1 Comment

I am facing the same issue. if it is possible, can you please share your code of "implementing the ImageLoader cache"?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.