【问题标题】:ListView shows wrong and duplicates imagesListView 显示错误并重复图像
【发布时间】: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 之类的东西将图像异步加载到图像视图中。您可以将您发布的所有代码更改为一行。

标签: android listview android-listview android-imageview android-image


【解决方案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 内部

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-30
      • 2013-08-07
      • 1970-01-01
      • 2011-01-08
      • 1970-01-01
      • 2019-09-17
      • 1970-01-01
      • 2020-11-30
      相关资源
      最近更新 更多