Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Picasso loads into wrong imageview when using view holder pattern

I'm trying to use the Picasso library to load external images into rows in a ListView. I have a custom ArrayAdapter as follows:

public class RevisedBusinessesAdapter extends ArrayAdapter<HashMap<String, String>> {

    Context context;
    int layoutResourceId;
    ArrayList<HashMap<String, String>> data = null;

    public RevisedBusinessesAdapter(Context context, int layoutResourceId,  ArrayList<HashMap<String, String>> data) {
        super(context, layoutResourceId, data);
        this.layoutResourceId = layoutResourceId;
        this.context = context;
        this.data = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;
        RevisedBusinessHolder holder = null;

        if (row == null) {
            LayoutInflater inflater = ((Activity) context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);
            holder = new RevisedBusinessHolder();
            holder.ivLogo = (ImageView) row.findViewById(R.id.ivBusinessLogo);
            row.setTag(holder);
        } else {
            holder = (RevisedBusinessHolder) row.getTag();
        }

        HashMap<String, String> business = data.get(position);

        String strLogoURL = business.get("logoURL");
        if (null != strLogoURL && !"".equals(strLogoURL)) {
            Picasso.with(this.context).load(strLogoURL).into(holder.ivLogo);        
        }

        return row;
    }

    static class RevisedBusinessHolder {
        ImageView ivLogo;
    }
}

where logoURL is an URL for a remotely located image; if not supplied, ivBusinessLogo has a local src set, and that is shown instead. When I scroll quickly, Picasso loads the image into the wrong ImageView and I end up with multiple copies of it in the list.

The answer to this question suggests adding

Picasso.with(context).cancelRequest(holder.ivLogo);

before the existing Picasso call, but that doesn't make any difference. If I remove the row == null check and always create a new view, it appears to work fine. In the full version of this, though, there are also four textviews and five other images (small icons loaded from local resources, not via Picasso) that need to be updated in each getView.

Is there a way to make this work with the View Holder pattern the Android documentation recommends?

like image 530
Ben Williams Avatar asked Oct 14 '14 11:10

Ben Williams


People also ask

How will you load an image into an imageView from an image URL using Picasso?

Image loading using Picasso is very easy, you can do it like this way Picasso. get(). load("http://i.imgur.com/DvpvklR.png").into(imageView); and in their website you can get every details. In your case you can parse every image URL and use RecyclerView to show them along with Picasso.


2 Answers

You should always call Picasso, even if your URL is null. This way it knows that the image view was recycled.

Delete this if statement:

if (null != strLogoURL && !"".equals(strLogoURL)) {

You should also consider using a placeholder image or an error image so that something will be displayed when there is no URL.

If you insist on keeping the if statement (but you shouldn't!), you need to tell Picasso that the image view was recycled by calling cancelRequest:

Picasso.with(this.context).cancelRequest(holder.ivLogo);
like image 67
Jake Wharton Avatar answered Sep 21 '22 12:09

Jake Wharton


The default src drawable set in the layout.xml (on ImageView) is beeing override by the last cached dowload image if the current item doesnt have a image to be download from the url.

You must manually set the default drawable for itens that dont have a image atribute:

try {
     Picasso.with(activity.getApplicationContext()).load(customer.getImage().getPath()).placeholder(R.drawable.image_placeholder)
                .error(R.drawable.image_placeholder).into(imageView);
    }
catch (Exception e) {
       imageView.setImageResource(R.drawable.default_customer_icon);
       // this set the default img source if the path provided in .load is null or some error happened on download.
    }
like image 24
Renato Probst Avatar answered Sep 20 '22 12:09

Renato Probst