So I recently wanted to try out the caching feature of the Picasso library, & I got into this confusing situation:
I retrieve the images' file names & paths  from my web server (using Retrofit2), & I store them into ImageComponent objects (model):
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
}
So now that the loading is successful, I populate a RecyclerView with these images using Picasso. The loading and inflation process is successful, but it gets a little tricky when caching the images.
Case1: using android.util.LruCache
(For convenience, I will post the entire code of the Recyclerview's adapter. I will try to be concise)
// 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
    }
}
RESULT1
(Notice those 2 last images, & how they show other previous images before displaying the correct one)
A few notes:
- I ran across a problem, where the images weren't displayed at all. After some research, I found this answer which suggested binding the targetto theImageView. (worked)
- I didn't quite understand how Picasso caches the images. Is it an automatic or manual process ? This answer states that Picasso handles this task for you. But when I actually tried it out (without the android Lrucache), no caching seemed to be done : The images were getting reloaded every time I scroll back & forth.
- Actually I was going to post a second use case where things went even more wrong, using the Picasso's Lrucache(images were being shown randomly , & change with every scroll), but I think this post is already long enough.
My questions are:
- Why do I get that weird behavior ? (as shown in the attached GIF)
- How does this whole caching process work ? Should I (or could I) use a Lrucache when making use of Picasso ?
- What's the difference between the Lrucachethat comes with the SDK & Picasso's ? (Performance, best use case scenarios, etc...)

 
     
    