ListView shows wrong and duplicates images

2019-06-27 20:56发布

I have a ListView and 12 ImageViews in it.

Every ImageView has different image which is loading from url. Images are shuffled and sometimes duplicated either I scroll or not.

I tried 10 other ways to solve this problem but have not succeeded.

This is the code I download and show images:

private static class ViewHolder {
    ImageView imageViewPhoto;

    Bitmap photo;
    boolean isDownloading;
}

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

    if (convertView == null) {

        // ...classical view holder and other operations...

        if (!viewHolder.isDownloading) {

            viewHolder.isDownloading = true;

            IImageDownload downloadInterface = new IImageDownload() {

                @Override
                public void onError(VolleyError error, String url) {
                }

                @Override
                public void onDownloaded(Bitmap response, String url) {

                        viewHolder.photo = response;
                    notifyDataSetChanged();
                }
            };

            imageDownloader.downloadImage(dataList.get(position).getPhotoPath(), true, downloadInterface);

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



    if (viewHolder.photo != null) {
        viewHolder.imageViewPhoto.setImageBitmap(viewHolder.photo);
    } else {
        viewHolder.imageViewPhoto.setImageResource(R.drawable.gray_background);
    }

}

Thanks in advance for any ideas!

4条回答
\"骚年 ilove
2楼-- · 2019-06-27 21:02

Use UniversalImageLoader library to load images.. Try this

ImageLoader.getInstance().displayImage(url, holder.imgView, options);

to load images inside adapter..

Use DisplayImageOptions as follows inside constructor of adapter

  options = new DisplayImageOptions.Builder()
                .showImageOnLoading(android.R.color.transparent)
                .showImageForEmptyUri(android.R.color.transparent)
                .showImageOnFail(android.R.color.transparent)
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .considerExifParams(true)
                .bitmapConfig(Bitmap.Config.RGB_565)
                .build();

and add

  StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);

inside onCreateView/onCreate of fragment/activity contaning the list

查看更多
相关推荐>>
3楼-- · 2019-06-27 21:04

You should have something like this:

if (!viewHolder.isDownloading) {
    // download the image in a worker thread
} else {
    // cancel the current downloading and start a new one with the new url
}

Since ListView items are reusable. Your items are starting the image downloads, but when you start scrolling, those same items could still be downloading the images when they are already being reused. So when the worker thread has finished, the bitmaps are set in the wrong place and even worse, you never started the downloads for those reused items because the viewholder.isDownloading said it was already downloading an image.

查看更多
来,给爷笑一个
4楼-- · 2019-06-27 21:11

A) You only initiate the download when the convertView is instantiated. You are recycling the rows so you may have a data set larger than the number of row Views that you actually use. This is not the right place to begin downloading an image. You want to do this per viewed position, not per View instantiated.

B) When you fire off a background task to download the image it may return later (after fetching) and replace a row with the wrong image as the row may now represent the wrong position (given row recycling).

Asynchronous image loading in a recycling ListView is slightly more complicated than it first seems. As the user scrolls through the list, you'll need to fire off downloads when a position is viewed, and cancel calls that are now redundant (as they are for a previously visible position).

You may wish to read more on view recycling in a ListView to get a better understanding of what is happening.

Also consider using an image downloading/caching library that handles these complexities such as Picasso.

查看更多
老娘就宠你
5楼-- · 2019-06-27 21:23

Before:

imageDownloader.downloadImage(dataList.get(position).getPhotoPath(), true, downloadInterface);

Put:

viewHolder.photo.setImageBitmap(null);

This will reset the ImageView's bitmap, as it is being recycled and therefore keeping its image.

查看更多
登录 后发表回答