我已经实现了一个RecyclerView,主要包含通过Picasso加载的图像。我的问题是,只要我向下或向上滚动视图,占位符图像就会显示约。在它被实际图像替换之前的一秒钟。它滚动非常顺利,但实际上无法使用。每次滚动屏幕时都会发生这种情况。
Picasso显然将图像缓存到磁盘,因为它们的加载速度比初始加载时间快,但它们肯定会立即从缓存中重新加载。我做错了什么?
我的适配器代码:
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;
}
}
}
感谢任何帮助。
答案 0 :(得分:67)
如下设置recyclerView参数解决了我的口吃问题:
recyclerView.setHasFixedSize(true);
recyclerView.setItemViewCacheSize(20);
recyclerView.setDrawingCacheEnabled(true);
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
我希望它也可以帮助别人。
答案 1 :(得分:27)
使用fit()
。
Picasso.with(context)
.load(file)
.fit()
.centerCrop()
.into(imageView);
fit()
实际调整图片大小以适应imageView
的范围。这不会加载整个图像并使滚动变得平滑。
答案 2 :(得分:8)
我把@ergunkocak和@Mangesh Ghotage的答案混合在一起,使用的效果非常好:
recyclerView.setHasFixedSize(true);
recyclerView.setItemViewCacheSize(20);
recyclerView.setDrawingCacheEnabled(true);
这在每张图片上都有:
Picasso.with(context)
.load(file)
.fit()
.into(imageView);
除了你可以设置Picasso使用这样的单个实例:
Picasso.setSingletonInstance(picasso);
最后启用缓存指标将为您提供有关出错的线索:
Picasso
.with(context)
.setIndicatorsEnabled(true);
答案 3 :(得分:3)
我最近遇到过这个问题,是的,你是对的。 Picasso是一个很好的库,用于显示来自SD卡的图像,但是如果你在线提取图像,它有一些关于缓存的问题,这就是你在滚动时看到占位符图像的原因。我尝试了不同的东西,问题没有解决。
有一个备用库,即“AQuery”,非常适合从网络中获取和缓存图像。
http://code.google.com/p/android-query/
AQuery / Android Query的主要优点是可以清除缓存,滚动时没有延迟,对于缓存图像非常有效,并且在滚动时不显示占位符图像。
我通过删除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中却没有,语法几乎相同。所以我建议你使用AQuery,直到这由picasso修复。
答案 4 :(得分:1)
我无法验证此解决方案的正确性,但我也遇到了这个问题并按照这个想法接近了它:
@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无法显示任何内容,否则禁止Picasso加载任何内容。
答案 5 :(得分:1)
毕加索自动将图像分为两个级别:
它们是使用默认设置初始化的机器人,适用于大多数应用程序。
当内存缓存变得太大时,从内存缓存中删除最旧的使用位图(默认情况下是可用堆空间的1/7)。
我认为这里发生的事情是您接近缓存的内存限制,因此每次需要时都会再次解码图像。
见这里: Android Picasso Configure LruCache Size
但我建议AGAINST增加内存缓存大小,除非你真的要将图像重新调整为你使用的实际大小..
我认为您的代码存在问题:
.resize(deviceWidth, deviceWidth)
你确定你真的需要这么大的图像吗?
你在PrefUtils中存储了什么?设备旋转时会更新吗? (风景与肖像)
如果您需要较小的图像,请尝试调整您要使用的图像的实际大小。如果您不知道(在运行时使用布局计算)使用近似值或编写代码来获取实际大小(我通常会为这些内容编写扩展ImageView的自定义类)。
如果你真的需要那个大小的图像,只需增加缓存大小(见上面的链接),你就应该好了。
答案 6 :(得分:0)
此问题的最佳答案是不使用圆形图像视图,而仅使用简单图像视图进行转换,因为圆形图像视图应用程序占用大量内存,仅使用简单图像视图并对其设置转换。 Use this transformation
答案 7 :(得分:0)
使用滑行。与毕加索不同,它缓存调整大小后的图像,而不是全尺寸图像。 用这种方法,您将失去图像质量。如果要保留原尺寸的质量,建议您使用Glide将图像加载并将其保存到文件存储中,因此,每当需要原尺寸的图像时,只需从文件存储中访问该图像即可。
答案 8 :(得分:-3)
只需使用as! *insertViewControllerClassName*
属性。