1

所以我最近想尝试一下毕加索库的缓存功能,我遇到了这个令人困惑的情况:

我从我的网络服务器(使用 Retrofit2)检索图像的文件路径ImageComponent,并将它们存储到对象(模型)中:

public class ImageComponent {

    private int id; // 'id' in database
    private String filename; // image name
    private String path; // image path in server storage
    private Bitmap bitmap;

    // Overloaded constructor

    // Getters & setters

}

所以现在加载成功了,我使用PicassoRecyclerView填充这些图像。加载和膨胀过程是成功的,但是在缓存图像时会有点棘手。

案例1:使用android.util.LruCache

(为方便起见,我会贴出整个Recyclerview适配器的代码,我会尽量简洁)

// imports
import android.util.LruCache;

public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder> {

    private Context mContext; // Activity's context
    private List<ImageComponent> mImages; // The imageComponents to display

    // The contreversial, infamous cache
    private LruCache<Integer, Bitmap> mImageCache; 

    public ImageAdapter(Context context, List<ImageComponent> images) {
        mContext = context;
        mImages = images;

        // Provide 1/8 of available memory to the cache
        final int maxMemory = (int)(Runtime.getRuntime().maxMemory() /1024);
        final int cacheSize = maxMemory / 8;
        mImageCache = new LruCache<>(cacheSize);
    }

    @Override
    public ImageAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // Nothing special
    }

    @Override
    public void onBindViewHolder(final ImageAdapter.ViewHolder holder, final int position) {
        // Current ImageComponent
        ImageComponent imageComponent = mImages.get(position);

        // Full image path in server storage
        String imagePath = Constants.SERVER_IP_ADDRESS + Constants.UPLOADS_DIRECTORY
                + imageComponent.getPath();

        // Display the file's name
        holder.text.setText(imageComponent.getFilename());

        final ImageView imageView = holder.image;

        // Get bitmap from cache, check if it exists or not
        Bitmap bitmap = mImageCache.get(imageComponent.getId());
        if (bitmap != null) {
            Log.i("ADAPTER", "BITMAP IS NOT NULL - ID = " + imageComponent.getId());
            // Image does exist in cache
            holder.image.setImageBitmap(imageComponent.getBitmap());
        }
        else {
            Log.i("ADAPTER", "BITMAP IS NULL");

            // Callback to retrieve image, cache it & display it
            final Target target = new Target() {
                @Override
                public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                    ImageComponent img = mImages.get(position);

                    // Display image
                    holder.image.setImageBitmap(bitmap);

                    // Cache the image
                    img.setBitmap(bitmap);
                    mImages.set(position, img);
                    mImageCache.put(img.getId(), bitmap);
                }

                @Override
                public void onBitmapFailed(Drawable errorDrawable) {
                }

                @Override
                public void onPrepareLoad(Drawable placeHolderDrawable) {
                }
            };

            // Tag the target to the view, to keep a strong reference to it
            imageView.setTag(target);
            // Magic
            Picasso.with(mContext)
                    .load(imagePath)
                    .into(target);
        }
    }

    @Override
    public int getItemCount() {
        return mImages.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        ImageView image;
        TextView text;

        // Constructor & view binding, not that special
    }
}

结果1

(注意最后两张图片,以及在显示正确图片之前它们如何显示其他先前的图片)

结果1

几点注意事项:

  • 我遇到了一个问题,根本没有显示图像。经过一番研究,我发现这个答案建议. (工作)targetImageView
  • 我不太明白毕加索是如何缓存图像的。是自动过程还是手动过程?该答案表明毕加索为您处理此任务。但是当我实际尝试时(没有 android Lrucache),似乎没有进行缓存:每次我来回滚动时,图像都会重新加载。
  • 实际上,我打算发布第二个用例,使用PicassoLrucache(图像随机显示,每次滚动都会更改),但我认为这篇文章已经足够长了。

我的问题是:

  1. 为什么我会出现这种奇怪的行为?(如附件GIF所示)
  2. 这整个缓存过程是如何工作的?在使用Picasso时我应该(或者我可以)使用 Lrucache吗?
  3. LrucacheSDK 自带的和Picasso的有什么区别?(性能、最佳用例场景等...)
4

1 回答 1

0
  1. 我认为同时使用 LRU 缓存和 Picasso 会导致奇怪的行为。我使用毕加索将图像缓存到适配器,它工作得很好。你可以在这里登记

  2. Picasso 与适配器一起使用时会自动缓存图像,它会像这样缓存,如果列表/回收器视图的子项不可见,它将停止为相应的子项缓存图像。所以最好单独使用 Picasso 和适配器。

  3. Picasso 在 LRU 缓存上的主要用途是,Picasso 易于使用。ex : 在 Picasso 中指定内存缓存大小。

    Picasso picasso = new Picasso.Builder(context)
                              .memoryCache(new LruCache(250))
                              .build();
    

Picasso 还允许您在下载出现错误时使用图像通知用户,这是在加载完整图像之前 Imageview 的默认持有者。

希望能帮助到你。

于 2015-12-06T14:48:30.273 回答