我尝试使用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模式来实现此功能?
答案 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;你会先看到错误的回收图像。