BaseAdapter 和毕加索问题

Posted

技术标签:

【中文标题】BaseAdapter 和毕加索问题【英文标题】:BaseAdapter and Picasso issue 【发布时间】:2015-04-01 06:35:57 【问题描述】:

我在使用 Picasso 从服务器加载 ListView 中的图像时遇到问题。

我有一个用于填充我的 ListView 的 BaseAdapter。在这个 ListView 中,有些项目有图片,有些没有。

在这个方法中:

public View getView(final int position, View convertView, ViewGroup parent) 

我愿意:

 ...

//context = Activity context;
//context1 = Context context1;
context1 = context.getApplicationContext();

 if (!photo[position].equals("")) 

    String stringurl = "http://www.blablabla.it/img/"+photo[position]+".jpg";

    Picasso.with(context1)
           .load(stringurl)
           .placeholder(R.drawable.white)
           .into(holder.imageD);
        
 else 

    holder.imageD.setImageBitmap(null);
 

此代码有效,但我经常看到图像位于与其所属位置不同的位置!

您可以想象这对用户来说非常烦人.. 谢谢大家

【问题讨论】:

您还应该在 else 语句中使用 Picasso 调用...然后应该取消对 holder.imageD 的任何加载请求... @Selvin 所以我应该写: holder.imageD.setImageBitmap(null);如果(...)毕加索...?可以举个例子吗? else Picasso.with(context1) .load(null) .placeholder(R.drawable.white) .into(holder.imageD); @Selvin 写:else holder.imageD.setImageBitmap(null); 不是一回事吗? 不!你看我的评论了吗? 【参考方案1】:

您遇到过这个问题,因为 ListView 回收项目视图 + Picasso 调用是异步的......它怎么会出现?

    开始用毕加索加载 视图被重用(convertView != null) 您正在设置holder.imageD.setImageBitmap(null); 从第 1 点异步完成。

这就是为什么您加载了错误的图像...

为避免此类行为,您需要通知 Picasso 加载程序取消先前的请求。 因此,只需将图像位图设置为 null,您必须通过 Picasso 库进行设置(在 else 语句中使用):

Picasso.with(context1).load(null).placeholder(R.drawable.white).into(holder.imageD);

编辑:遵循@Budius cmets:更好的解决方案将是取消并设置,例如:


  Picasso.with(context1).cancelRequest(holder.imageD);
  //holder.imageD.setImageBitmap(null); //or
  holder.imageD.setImageResource(R.drawable.white); //depends on your needs

这应该是更有效的方式,因为它应该在每次 getView 调用时创建更少的内部对象。

【讨论】:

我认为最好手动将图像设置为 null 并通知 Picasso 取消请求 Picasso.with(c).cancelRequest(holder.imageD); holder.imageD.setImageBitmap(null); 您的方式似乎是无缘无故地创建新请求。 @Budius ...“新请求”是什么意思? (来自 piccasso 库的请求对象或一些网络请求?)事实上,它与“into”中的代码几乎相同:if (!data.hasImage()) picasso.cancelRequest(target); target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null); return; ,如果 uri 为 null,则 hasImage 返回 false ...所以不会有网络使用的操作(如果事实上,它将是同步调用)......我的版本也将使用占位符代替空位图 我的意思是库中的 new RequestCreator 对象。从源代码行#293 if (path == null) return new RequestCreator(this, null, 0); 和行#569 上的private void cancelExistingRequest(Object target) 代码简单地取消现有的。我知道这些很小,但想象一下滚动数千个项目的列表和 GC 必须运行以删除所有这些小对象。关于占位符:也可以在 ImageView 上调用setImageResource(R....)(来源:github.com/square/picasso/blob/master/picasso/src/main/java/com/…) 好的 ...我已将您的 cmets 添加到答案中...仍然想知道占位符是否以某种方式缓存...并且 android 框架是否正在缓存 setImageResource ...如果答案是肯定的不,那么第一个版本可能会更有效:)

以上是关于BaseAdapter 和毕加索问题的主要内容,如果未能解决你的问题,请参考以下文章

毕加索在 ListFragment 中有很多大位图

[完成]notifyDataSetChanged() 不会自动更新 ListActivity

Fragment和BaseAdapter之间的Android通信

自定义BaseAdapter如何重写getItem和getItemId

如何将数据添加到 listView 的自定义 BaseAdapter - Android

使用 CardView BaseAdapter OnItemClick 自定义 ListView