我有一个自定义ArrayAdapter,可以从网络上获取图像。我知道这些观点得到了回收。我的代码似乎有效,但是从网络加载的图像存在问题。有时,错误的图像可能会显示另一行。例如,米老鼠可能是第0行上的图像,当我向下滚动时,在转换为唐老鸭之前,第9行(示例)可能会短暂出现米老鼠。当我向后滚动到顶部时,唐老鸭可能会出现在第0行,然后再换回米老鼠。
这是我的代码:
class OffersCustomAdapter extends ArrayAdapter<Merchant>{
Context context;
ArrayList<User> userName;
private LayoutInflater inflater;
private ImageLoadingListener animateFirstDisplayListener;
private ImageLoader imageLoader;
public OffersCustomAdapter(Context c, ArrayList<User> users) {
super(c, R.layout.single_row, users);
this.context=c;
this.userName=users;
imageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(context));
}
static class ViewHolder{
TextView title;
TextView cat;
TextView type;
TextView desc;
ImageView pic;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public int getItemViewType(int position) {
return position;
}
@Override //parent is listview
public View getView(int position, View convertView, ViewGroup parent) {
View row=convertView;
ViewHolder viewHolder;
if(convertView == null){
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//row contains our relative layout
row =inflater.inflate(R.layout.single_row, parent, false);
viewHolder = new ViewHolder();
viewHolder.title =
(TextView) row.findViewById(R.id.textView1);
viewHolder.pic = (ImageView) row.findViewById(R.id.imageView1);
row.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder = (ViewHolder) row.getTag();
User u = userName.get(position);
String titleSt = userName.get(position).getName();
viewHolder.title.setText(titleSt);
imageLoader.displayImage(imageUrl+userName.get(position).getImg(), viewHolder.pic, animateFirstDisplayListener);
return row;
}
我看过SO的其他例子,但没有运气。
答案 0 :(得分:3)
这是因为视图正在被回收。向下滚动时,出现的下一个视图将使用刚刚滚出视图的相同视图(即米老鼠)。您可以在imageLoader
获取新图片时显示加载图片来解决此问题。
如果您没有加载图片,可以在getView(...)
方法的开头执行以下操作:
viewHolder.pic.setImageDrawable(null);
编辑:根据评论修复。
答案 1 :(得分:1)
这可能是因为如果在视图被回收时仍在进行中,之前的图像加载操作不会被取消,因此这会在设置视图的位图时引入竞争条件。本文将简要讨论此问题,可能值得一读:Multithreading for Performance
作者更详细地解释了它:
但是,特定于ListView的行为会显示我们的问题 目前的实施。的确,出于内存效率的原因, ListView回收用户滚动时显示的视图。 如果一个人翻转列表,则会使用很多给定的ImageView对象 倍。每次显示时,ImageView都会正确触发 图像下载任务,最终将改变其图像。那么在哪里 是问题吗?与大多数并行应用程序一样,关键问题是 在订购中。在我们的例子中,不保证下载 任务将按照启动顺序完成。结果 是最终显示在列表中的图像可能来自a 上一个项目,它恰好花了更长的时间下载。 如果您下载的图像被绑定一次,那么这不是问题 所有给予ImageViews,但让我们解决它的常见情况 它们用在列表中。
并提供可能有帮助的解决方法示例。
答案 2 :(得分:0)
尝试picasso
在工作区中安装jar后,您只需要一行代码。
替换imageLoader.displayImage(imageUrl+userName.get(position).getImg(), viewHolder.pic, animateFirstDisplayListener);
与
Picasso.with(context).load(your_image_Url).into(viewholder.pic);
我认为your_image_url
<{1}}就是imageUrl+userName.get(position).getImg();
答案 3 :(得分:0)
有一篇为期5年的Android博文,介绍了如何手动解决这个问题,Multithreading for Performance。
如今,您应该使用Picasso或Volley进行图像加载。这些网络API可以轻松解决您的问题,并为您提供额外的好处,例如缓存。 Volley是Google在自己的应用程序中使用的API。我在我的应用程序中使用它并且是粉丝。