使用视图持有者模式时,毕加索会加载到错误的imageview中

时间:2014-10-14 11:21:23

标签: android picasso

我尝试使用Picasso库将外部图像加载到ListView中的行中。我有一个自定义ArrayAdapter,如下所示:

public class RevisedBusinessesAdapter extends ArrayAdapter<HashMap<String, String>> {

    Context context;
    int layoutResourceId;
    ArrayList<HashMap<String, String>> data = null;

    public RevisedBusinessesAdapter(Context context, int layoutResourceId,  ArrayList<HashMap<String, String>> data) {
        super(context, layoutResourceId, data);
        this.layoutResourceId = layoutResourceId;
        this.context = context;
        this.data = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;
        RevisedBusinessHolder holder = null;

        if (row == null) {
            LayoutInflater inflater = ((Activity) context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);
            holder = new RevisedBusinessHolder();
            holder.ivLogo = (ImageView) row.findViewById(R.id.ivBusinessLogo);
            row.setTag(holder);
        } else {
            holder = (RevisedBusinessHolder) row.getTag();
        }

        HashMap<String, String> business = data.get(position);

        String strLogoURL = business.get("logoURL");
        if (null != strLogoURL && !"".equals(strLogoURL)) {
            Picasso.with(this.context).load(strLogoURL).into(holder.ivLogo);        
        }

        return row;
    }

    static class RevisedBusinessHolder {
        ImageView ivLogo;
    }
}

其中logoURL是远程图像的URL;如果没有提供,ivBusinessLogo有一个本地src设置,而是显示。当我快速滚动时,Picasso会将图像加载到错误的ImageView中,最后我会在列表中找到它的多个副本。

this问题的答案建议添加

Picasso.with(context).cancelRequest(holder.ivLogo);
在现有的毕加索电话会议之前,但这并没有任何区别。如果我删除row == null检查并始终创建新视图,它似乎工作正常。但是,在完整版本中,还有四个文本视图和五个其他图像(从本地资源加载的小图标,而不是通过毕加索),需要在每个getView中进行更新。

有没有办法使用Android documentation推荐的View Holder模式来实现此功能?

4 个答案:

答案 0 :(得分:22)

即使您的网址为null,也应始终致电Picasso。这样它就知道图像视图已被回收。

删除此if声明:

if (null != strLogoURL && !"".equals(strLogoURL)) {

您还应考虑使用占位符图片或错误图片,以便在没有网址时显示某些内容。

如果你坚持保留if声明(但你不应该!),你需要告诉Picasso通过调用cancelRequest来回收图片视图:

Picasso.with(this.context).cancelRequest(holder.ivLogo);

答案 1 :(得分:2)

如果当前项目没有要从网址下载的图像,则layout.xml(在ImageView上)中的默认src drawable设置将被最后一个缓存的下载图像覆盖。

您必须为没有图像属性的itens手动设置默认drawable:

try {
     Picasso.with(activity.getApplicationContext()).load(customer.getImage().getPath()).placeholder(R.drawable.image_placeholder)
                .error(R.drawable.image_placeholder).into(imageView);
    }
catch (Exception e) {
       imageView.setImageResource(R.drawable.default_customer_icon);
       // this set the default img source if the path provided in .load is null or some error happened on download.
    }

答案 2 :(得分:0)

我有同样的问题并修复了它。请考虑getView方法

中的参数convertView
  如果可能的话,

convertView是旧视图以便重用。注意:你应该检查   在使用之前,此视图为非null且具有适当的类型。如果   无法转换此视图以显示正确的数据,   此方法可以创建新视图。

当你使用holder时,Picasso会将图像加载到一行的imageview并重新使用它。这就是你看到重复图像的原因。 在我看来,你应该在第一次创建行视图时加载你的图像。尝试将代码更改为

if (row == null) {
    LayoutInflater inflater = ((Activity) context).getLayoutInflater();
    row = inflater.inflate(layoutResourceId, parent, false);
    holder = new RevisedBusinessHolder();
    ImageVIew ivLogo = (ImageView) row.findViewById(R.id.ivBusinessLogo);
    Picasso.with(this.context).load("Your Image URL").into(holder.ivLogo);
    row.setTag(holder);
}

答案 3 :(得分:-1)

在Picasso.with()。load()。into()语句后添加else语句。添加else holder.ivLogo.setImageBitmap(null);。或者使用占位符位图。

看过Octa George的解决方案后,最好在调用Picasso之前始终执行holder.ivLogo.setImageBitmap(placeholderbitmap);。否则当毕加索花费他的时间&#39;你会先看到错误的回收图像。