ListView 显示错误并重复图像

Posted

技术标签:

【中文标题】ListView 显示错误并重复图像【英文标题】:ListView shows wrong and duplicates images 【发布时间】:2014-06-19 09:18:25 【问题描述】:

我有一个 ListView 和 12 个 ImageView。

每个 ImageView 都有从 url 加载的不同图像。图像被打乱,有时我滚动或不滚动都会重复。

我尝试了 10 种其他方法来解决这个问题,但都没有成功。

这是我下载并显示图像的代码:

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);
    


提前感谢您的任何想法!

【问题讨论】:

不是您问题的答案,但您应该考虑使用 Picasso 之类的东西将图像异步加载到图像视图中。您可以将您发布的所有代码更改为一行。 【参考方案1】:

之前:

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

放:

viewHolder.photo.setImageBitmap(null);

这将重置 ImageView 的位图,因为它正在被回收并因此保留其图像。

【讨论】:

这个想法很合适! 执行 setImageBitmap(null) 将是万无一失的,尤其是当图像加载器加载图像时,它至少需要几秒钟。在下载过程中,listview / recyclerview 可能已经为另一个项目回收了 viewholder。【参考方案2】:

你应该有这样的东西:

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

因为 ListView 项目是 reusable。您的项目正在开始图像下载,但当您开始滚动时,这些相同的项目可能仍在下载已被重复使用的图像。因此,当工作线程完成时,位图设置在错误的位置,更糟糕的是,您从未开始下载那些重复使用的项目,因为 viewholder.isDownloading 表示它已经在下载图像。

【讨论】:

是不好的做法,如果您的互联网速度较慢,您将得到一个空图像:) 和更多错误:D【参考方案3】:

A) 只有在 convertView 被实例化时才开始下载。您正在回收这些行,因此您的数据集可能大于您实际使用的行数Views。这不是开始下载图像的正确位置。您希望按查看的位置执行此操作,而不是按 View 实例化。

B) 当您启动后台任务以下载图像时,它可能会稍后返回(在获取之后)并用错误的图像替换一行,因为该行现在可能代表错误的位置(给定行回收)。

回收ListView 中的异步图像加载比最初看起来要复杂一些。当用户在列表中滚动时,您需要在查看位置时触发下载,并取消现在多余的调用(因为它们是针对以前可见的位置)。

您可能希望在ListView 中阅读更多关于视图回收的信息,以更好地了解正在发生的事情。

还可以考虑使用处理这些复杂性的图像下载/缓存库,例如Picasso。

【讨论】:

【参考方案4】:

使用UniversalImageLoader 库加载图像.. 试试这个

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

在适配器内加载图像..

在适配器的构造函数中如下使用DisplayImageOptions

  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();

并添加

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

包含列表的片段/活动的 onCreateView/onCreate 内部

【讨论】:

以上是关于ListView 显示错误并重复图像的主要内容,如果未能解决你的问题,请参考以下文章

为啥偶尔会在 ListView 中加载错误的图像?

ScrollView嵌套listView,显示头像错乱

listview.setSelection()

c#listview添加控件时不显示滚动条

Android中的Listview延迟加载平滑[重复]

在 ListView 中使用 LazyList 时出现内存不足错误 [重复]