user3148156
user3148156

Reputation: 178

wrong images in listview because imageview is recycled

The code looks like this:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final Contact currContact = getItem(position);

    final ViewHolder viewHolder;
    if (convertView == null) {
        viewHolder = new ViewHolder();
        LayoutInflater inflater = LayoutInflater.from(getContext());
        convertView = inflater.inflate(R.layout.contact_item, parent, false);

        viewHolder.profileIV = (ImageView) convertView.findViewById(R.id.profileIV);
        viewHolder.nameTV = (TextView) convertView.findViewById(R.id.nameTV);

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
**************************PER JAKE WHARTON's RESPONSE******************************************
        Picasso.with(getContext()).cancelRequest(viewHolder.profileIV);
    }

    String currName = currContact.getName();

    /* 1 
       Asynchronously GETs https://ajax.googleapis.com/ajax/services/search/images? 
       rsz=8&start=0&v=1.0&imgsz=medium&imgtype=linear&q=(currName) */
    APIclient.getImageJson(getContext(), currName, new JsonHttpResponseHandler() {
        @Override
        public void onSuccess(int statusCode, Header[] headers, JSONObject imgJson) {
            try {
                JSONObject responseDataValue = imgJson.getJSONObject("responseData");
                JSONArray resultsValue = responseDataValue.getJSONArray("results");
                JSONObject result = resultsValue.getJSONObject(0);
                String imgUrl = result.getString("url");

                // 2
                Picasso.with(getContext()).load(imgUrl).into(viewHolder.profileIV);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
  1. The asynchronous call is launched, and the user scrolls down.
  2. The call completes, the image url is obtained, and Picasso makes ANOTHER GET request to render the image, but in the wrong imageview because of recycling

The only way I know to get around this is to make the first GET request(to obtain the image link) SYNCHRONOUS, blocking the ui to make sure getView isn't called again before the image is loaded. Is there a better way to get around this? Many thanks in advance.

Upvotes: 2

Views: 1307

Answers (1)

Jake Wharton
Jake Wharton

Reputation: 76125

The reason you are seeing this behavior is that you are only calling the Picasso object after making another asynchronous request. This means that Picasso has no way of knowing that the view was recycled for a new item.

The easiest way to solve this is by adding a call to Picasso to cancel existing requests for the recycled view.

Picasso.with(getContext()).cancelRequest(viewHolder.profileIV)

This should be done outside of the APIclient.getImageJson call so that it runs synchronously when the adapter is called.

Upvotes: 4

Related Questions