所以我最近想尝试一下毕加索库的缓存功能,我遇到了这个令人困惑的情况:
我从我的网络服务器(使用 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
(注意最后两张图片,以及在显示正确图片之前它们如何显示其他先前的图片)
几点注意事项:
- 我遇到了一个问题,根本没有显示图像。经过一番研究,我发现这个答案建议将. (工作)
target
ImageView
- 我不太明白毕加索是如何缓存图像的。是自动过程还是手动过程?该答案表明毕加索为您处理此任务。但是当我实际尝试时(没有 android Lrucache),似乎没有进行缓存:每次我来回滚动时,图像都会重新加载。
- 实际上,我打算发布第二个用例,使用Picasso的
Lrucache
(图像随机显示,每次滚动都会更改),但我认为这篇文章已经足够长了。
我的问题是:
- 为什么我会出现这种奇怪的行为?(如附件GIF所示)
- 这整个缓存过程是如何工作的?在使用Picasso时我应该(或者我可以)使用 Lrucache吗?
Lrucache
SDK 自带的和Picasso的有什么区别?(性能、最佳用例场景等...)