【问题标题】:Recyclerview painfully slow to load cached images form PicassoRecyclerview 从 Picasso 加载缓存的图像非常缓慢
【发布时间】:2014-11-11 02:28:16
【问题描述】:

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

感谢任何帮助。

【问题讨论】:

  • 顺便说一句 SquareImage 是什么?

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


【解决方案1】:

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

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

我希望它也可以帮助其他人。

【讨论】:

  • 这对我也有用。但我只使用了你的 2 和 3 行代码)
  • 这是一个很好的解决方案。
  • 解决了我的 recyclerview 滚动滞后的问题,非常感谢。
  • 这不是可扩展的解决方案,并且违背了回收者视图的目的
  • recyclerView.setDrawingCacheEnabled(true);已弃用
【解决方案2】:

使用fit()

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

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

【讨论】:

【解决方案3】:

我将@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

【讨论】:

  • Picasso.with(context) .load(file) .fit() .into(imageView);这救了我的命.....谢谢。
【解决方案4】:

我最近遇到了这个问题,是的,你是对的。 Picasso 是一个很好的库,用于显示来自 sdcard 的图像,但是如果您在线获取图像,它会出现一些关于缓存的问题,这就是您在滚动时看到占位符图像的原因。我尝试了不同的方法,但问题没有解决。

还有一个备用库,即“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);

此外,您还可以轻松地从 picasso 转移到 AQuery,因为 picasso 中没有这种东西,但 AQuery 中没有,而且语法几乎相同。所以我建议你使用 AQuery,直到毕加索解决这个问题。

【讨论】:

    【解决方案5】:

    毕加索自动将图片缓存在两个级别:

    • 磁盘缓存(这实际上不在毕加索中,而是在毕加索使用的网络层中)
    • 内存缓存

    它们使用适合大多数应用程序的默认值进行机器人初始化。

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

    我认为这里发生的情况是您接近缓存的内存限制,因此每次您再次需要它们时都会再次解码图像。

    请看这里: Android Picasso Configure LruCache Size

    但我建议不要增加内存缓存大小,除非您确实将图像大小重新调整为您使用的实际大小..

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

    .resize(deviceWidth, deviceWidth)
    

    你确定你真的需要这么大的图片吗? 你在 PrefUtils 中存储了什么?设备旋转时会更新吗? (横向与纵向)

    如果您需要较小的图像,请尝试将调整大小传递给您要使用的图像的实际大小。如果您不知道(在运行时使用布局计算),请使用近似值或编写代码以获得实际大小(我通常为这些东西编写扩展 ImageView 的自定义类)。

    如果您确实需要该大小的图像,只需增加缓存大小(请参阅上面的链接),您应该很高兴。

    【讨论】:

      【解决方案6】:

      我无法验证这个解决方案的正确性,但我也遇到了这个问题,并按照这个想法解决了这个问题:

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

      它旨在禁止 Picasso 加载任何内容,除非 ImageView 没有可显示的内容。

      【讨论】:

      • 我认为这行不通。当然,这适用于 RecyclerView 中的第一个元素,但对于所有其他元素,将显示相同的图像。
      • 好吧,对我不起作用。我的 ViewHolder 在 onBindViewHolder 方法中执行此操作。 image.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { GoTo.imageReelGalery(itemView.getContext(), v, 0, Image.toArray(publication.getImages())); } }); if (image.getDrawable() == null) PicassoHelper.downloadImage(itemView.getContext(),"http://" + publication.getImages()[0], image); 可能是因为我是从 url 加载的?
      • 要知道,我使用以下代码使其工作:Picasso picasso = Picasso.with(ctx); picasso.load(url).stableKey(url).tag(viewHolder).into(image); 之前是:Picasso picasso = Picasso.with(ctx); picasso.load(url).into(image);
      • 您对 RecyclerView ViewHolder 的方法是错误的。通过在 onBindViewHolder 中设置 onClickListener,您可以发出类似“每次呈现此视图时,告诉 imageview,当它被单击时,它应该加载图像”之类的命令。这就是上述解决方案对您不起作用的原因,并且您所说的“使它起作用”的方式也不正确,即使看起来像。 Here you are an example of proper RecyclerView ViewHolder pattern.
      • Jorge,考虑 ViewHolder 模式,您想回收视图,因此视图持有者将拥有已经填充的 ImageView - 使用另一个图像,即错误的图像。在您的代码中设置“viewHolder.imageView.setImageDrawable(null);”所以无论如何毕加索都会接到电话。如果(真);
      【解决方案7】:

      使用滑翔。与毕加索不同,它缓存调整大小的图像,而不是全尺寸图像。 在这种方法中,您将失去图像质量。如果你想保持全尺寸质量,我建议你使用 Glide 来加载图像并将其保存到文件存储中,所以当你需要全尺寸图像时,只需从文件存储中访问该图像即可。

      【讨论】:

        【解决方案8】:

        这个问题的最佳答案是不要使用圆形图像视图,只需使用简单图像视图的转换,因为圆形图像视图应用程序占用大量内存,只需使用简单图像视图并使用它设置转换。 Use this transformation

        【讨论】:

        • 通过变换,我们可以将图像设置为所需的形状。如何将视图设为圆形。即有一个圆形图像视图,用户单击以附加图像? @Rana Asad
        • @ArnoldBrown 如果想在用户单击图像视图选择图像后放置图像,然后将一些占位符设置为图像视图,它将像圆形图像视图一样工作。
        【解决方案9】:

        只需使用noPlaceholder 属性。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-05-16
          • 2014-04-09
          • 1970-01-01
          • 2019-02-11
          • 1970-01-01
          • 2020-03-31
          • 1970-01-01
          相关资源
          最近更新 更多