Recyclerview痛苦地缓慢加载从毕加索caching的图像

我已经实现了一个RecyclerView,主要包含通过Picasso加载的图像。 我的问题是,只要我向下滚动或向上的视图,占位符图像出现约。 一秒钟之后,它被实际的图像取代。 它滚动非常顺利,但实际上是无法使用的。 每当某个东西从屏幕上滚动时,就会发生这种情况。

毕加索显然将图像caching到磁盘上,因为它们的加载速度比初始加载时间要快,但是它们肯定会立即从caching中重新加载。 我错误地执行了什么?

我的适配器代码:

public class ExploreAdapter extends RecyclerView.Adapter<ExploreAdapter.ExploreViewHolder> { private List<ExploreItem> exploreItemList; private Context mContext; private int deviceWidth = PrefUtils.getDeviceWidth(); public ExploreAdapter(Context context, List<ExploreItem> exploreItemList){ this.mContext = context; this.exploreItemList = exploreItemList; } @Override public int getItemCount(){ return exploreItemList.size(); } @Override public void onBindViewHolder(ExploreViewHolder exploreViewHolder, int i){ ExploreItem item = exploreItemList.get(i); exploreViewHolder.getvTitle().setText(item.getTitle()); exploreViewHolder.getvUsername().setText(item.getUsername()); exploreViewHolder.getvNumLikes().setText(item.getNbOfLikes()); Picasso.with(mContext).load(item.getMediaLocation().trim()) .resize(deviceWidth, deviceWidth) .centerCrop() .placeholder(R.drawable.profile_background) .into(exploreViewHolder.getvImage()); Picasso.with(mContext).load(item.getUserProfilePicUrl().trim()) .placeholder(R.drawable.profile_picture) .into(exploreViewHolder.getvProfilePic()); } @Override public ExploreViewHolder onCreateViewHolder(ViewGroup viewGroup, int i){ View itemView = LayoutInflater. from(viewGroup.getContext()). inflate(R.layout.explore_item, viewGroup, false); return new ExploreViewHolder(itemView); } public static class ExploreViewHolder extends RecyclerView.ViewHolder{ private TextView vTitle, vUsername, vNumLikes; private SquareImage vImage; private ImageView vProfilePic; public ExploreViewHolder(View v){ super(v); this.vTitle = (TextView) v.findViewById(R.id.explore_item_title); this.vUsername = (TextView) v.findViewById(R.id.explore_item_username); this.vNumLikes = (TextView) v.findViewById(R.id.explore_item_number_likes); this.vImage = (SquareImage) v.findViewById(R.id.explore_item_image); this.vProfilePic = (ImageView) v.findViewById(R.id.explore_item_profile_picture); } public TextView getvTitle() { return vTitle; } public TextView getvUsername() { return vUsername; } public ImageView getvProfilePic() { return vProfilePic; } public SquareImage getvImage() { return vImage; } public TextView getvNumLikes() { return vNumLikes; } public void setvImage(SquareImage vImage) { this.vImage = vImage; } public void setvNumLikes(TextView vNumLikes) { this.vNumLikes = vNumLikes; } public void setvProfilePic(ImageView vProfilePic) { this.vProfilePic = vProfilePic; } public void setvTitle(TextView vTitle) { this.vTitle = vTitle; } public void setvUsername(TextView vUsername) { this.vUsername = vUsername; } } } 

任何帮助表示赞赏。

设置recyclerView参数如下解决了我的口吃问题:

 recyclerView.setHasFixedSize(true); recyclerView.setItemViewCacheSize(20); recyclerView.setDrawingCacheEnabled(true); recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH); 

我希望它也能帮助别人。

使用fit()

 Picasso.with(context) .load(file) .fit() .centerCrop() .into(imageView); 

fit()实际上调整了图像大小,以适应imageView的边界。 这不会加载完整图像并平滑滚动。

最近我遇到过这个问题,对,你是对的。 毕加索是一个很好的图书馆展示从SD卡的图像,但它有一些关于caching的问题,如果你在网上提取图像,这就是为什么你看到一个占位符图像,而滚动。 我尝试了不同的事情,问题没有解决。

还有一个替代库,即“AQuery”,它非常适合从networking获取和caching图像。

http://code.google.com/p/android-query/

AQuery / Android Query的主要优点是可以清除caching,滚动时没有滞后,对于caching图片非常有效,在滚动时不显示占位符图片。

我通过删除picaaso和使用Aquery来解决我的问题。 它只是一个线路更换,你完成了你的问题。

 (new AQuery(mContext)).id(exploreViewHolder.getvProfilePic()).image(item.getUserProfilePicUrl().trim(), true, true, device_width, R.drawable.profile_background, aquery.getCachedImage(R.drawable.profile_background),0); 

除此之外,你可以很容易地从毕加索转移到AQuery,因为毕加索没有这样的东西,而不是在AQuery中,而且语法几乎相同。 所以我build议你使用AQuery,直到被picasso修复。

我混合@ergunkocak和@Mangesh Ghotage的答案,使用这个工程很棒:

 recyclerView.setHasFixedSize(true); recyclerView.setItemViewCacheSize(20); recyclerView.setDrawingCacheEnabled(true); 

这在每个图像上:

 Picasso.with(context) .load(file) .fit() .into(imageView); 

除此之外,你可以设置毕加索使用这样一个单一的实例:

 Picasso.setSingletonInstance(picasso); 

最后启用caching指标将为您提供有关错误的线索:

 Picasso .with(context) .setIndicatorsEnabled(true); 

更多关于毕加索

我无法validation这个解决scheme的正确性,但我也遇到了这个问题,并按照这个想法来处理:

 @Override public void onBindViewHolder(ViewHolder viewHolder, final int i) { ... if(mImageView.getDrawable == null()){ Picasso.with(context) .load(path) .error(errorResId) .tag(tag) .into(mImageView); } ... 

}

它的目的是禁止毕加索加载任何东西,除非ImageView没有任何显示。

毕加索自动caching两个级别的图像:

  • 磁盘caching(这实际上不是在毕加索,而是在毕加索使用的networking层)
  • 内存caching

他们是僵尸程序初始化与大多数应用程序套件的默认值。

当内存caching变得太大时,最旧的位图将从内存caching中删除(默认为可用堆空间的1/7)。

我认为这里发生的事情是,你已经接近caching的内存限制,因此图像每当你再次需要时都会被解码。

请参阅: Android PicassoconfigurationLruCache大小

但我build议反对增加内存caching大小,除非你真的重新resize的图像到您使用的实际大小..

我认为你的代码的问题是这样的:

 .resize(deviceWidth, deviceWidth) 

你确定你真的需要这个尺寸的图像吗? 你在PrefUtils中存储什么? 设备旋转时会不会更新? (风景vs肖像)

如果您需要较小的图像,请尝试通过调整要使用的图像的实际大小。 如果你不知道(在运行时与布局计算)做一个近似或编写代码来获取实际大小(我通常编写自定义类扩展ImageView这些东西)。

如果你真的需要这种大小的图像,只是增加caching大小(见上面的链接),你应该很好去。

只使用noPlaceholder属性。