Images loaded in Listview are changing randomly

Asked

Viewed 85 times

1

I implemented a Listview where an external image is populated in each position, but when I scroll the screen the images are changing randomly.

This video shows exactly what happens: https://vid.me/u1Oc

Note: there should be no repeat image in Listview.

Downloadtask:

public class DownloadTask extends AsyncTask<String, Void, Bitmap> {
    private final WeakReference<ImageView> imageView;

    public DownloadTask(ImageView thumbnail)
    {
        imageView = new WeakReference<ImageView>(thumbnail);
    }

    @Override
    protected Bitmap doInBackground(String... params)
    {

        try {
            InputStream strem = new URL(params[0]).openConnection().getInputStream();
            return BitmapFactory.decodeStream(strem);
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap)
    {
        ImageView thumbnail = imageView.get();

        if (thumbnail != null)
        {
            if (bitmap != null)
            {
                thumbnail.setImageBitmap(bitmap);
            }
        }
    }
}

Adapter:

public class Adapter extends SimpleAdapter {
    public LayoutInflater inflater = null;

    public Adapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)
    {
        super(context, data, resource, from, to);

        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public View getView(int position, View view, ViewGroup parent) {
        ViewHolder viewHolder;

        HashMap<String, Object> data = (HashMap<String, Object>) super.getItem(position);

        if(view == null){
            view = inflater.inflate(R.layout.clientes, parent, false);

            viewHolder = new ViewHolder();

            viewHolder.thumbnail = (ImageView) view.findViewById(R.id.thumbnail);
            viewHolder.title = (TextView)view.findViewById(R.id.title);
            viewHolder.content = (TextView)view.findViewById(R.id.content);

            view.setTag(viewHolder);
        }else{
            viewHolder = (ViewHolder)view.getTag();
        }

        new DownloadTask(viewHolder.thumbnail).execute(data.get("thumbnail").toString());

        viewHolder.title.setText(data.get("title").toString());
        viewHolder.content.setText(data.get("content").toString());

        return view;
    }

    static class ViewHolder{
        ImageView thumbnail;
        TextView title;
        TextView content;
    }
}
  • You can show how your Adapter? I believe the problem goes through him.

  • Yes, I updated with the Adapter in the description.

1 answer

5


Rafael, this problem is expected by the way it was implemented.

You are not doing any treatment to check if at the end of the download, that image should still be shown for that Imageview.

This is due to Listview’s behavior of reserving a fixed amount of Views to be reused. So you can have two Tasks with the same reference for a particular Imageview.

To solve, there are two ways:

  • Use a lib to upload images, and there are dozens: Picasso, Glide, Universal Image Loader, Volley itself, Fresco and etc...

    I think it’s the best alternative, no need to reinvent the wheel, because you can even handle cache and many other things, which is valuable in the mobile world. And these libs have an algorithm for this type of recycling treatment from Listview.

  • If you are going to do it using Task, I recommend to mark the View (tag) with some Task key, because at the end of the Download you can check this key and compare with the current Task key, if it is equal, arrow the normal Bitmap, otherwise ignore.

  • I used Picasso to download the image, fixed perfectly.

  • Well put, I knew it was because of the reuse of views but it hadn’t occurred to me that Asynctask can have a reference that already belongs to another line.

  • 2

    Yes, I’ve had to do this kind of treatment because in my case I had a Task that generated Qrcode and not download images, I had to do this treatment in hand...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.