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

时间:2014-11-11 02:28:16

标签: java android android-recyclerview android-5.0-lollipop picasso

我已经实现了一个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;
        }
    }
}

感谢任何帮助。

9 个答案:

答案 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);

More about Picasso

答案 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*属性。