A picture is worth a thousand words. That’s also true for many apps out there. To make image loading easy and hassle-free, using a library is recommended. My personal favorite is Picasso by Square. From showing a placeholder while downloading pictures to resizing and caching images, everything is handled by the library. To use it, add a dependency to your module’s gradle.build file:
compile 'com.squareup.picasso:picasso:2.5.2'
That’s it. You’re ready to go. Let’s load a picture into an ImageView:
Picasso.with(context.getApplicationContext()) .load(url) .placeholder(R.drawable.img_placeholder) .error(R.drawable.img_error) .into(imageView);
With this call, a placeholder drawable is displayed while the image is downloaded. Afterwards the picture is faded in. If an error occurs while downloading, the error drawable is shown. This is the base use case of Picasso. But the library has many advanced features. With .fit(), Picasso automatically resizes the image to the dimensions of the ImageView, which is more memory efficient. Also, you can use .resize(width, height) to resize the picture manually – here you can also use .onlyScaleDown(). When resizing, .centerCrop() and .centerInside() are also provided.
Another nice feature is the possibility to pause picture downloads while scrolling. This is achieved via scrolling tags, which can be applied to requests. For example, the following RecyclerView.OnScrollListener can be used:
public class PicassoOnScrollListener extends RecyclerView.OnScrollListener { public static final Object TAG = new Object(); private static final int SETTLING_DELAY = 500; private static Picasso sPicasso = null; private Runnable mSettlingResumeRunnable = null; public PicassoOnScrollListener(Context context) { if(this.sPicasso == null) { this.sPicasso = Picasso.with(context.getApplicationContext()); } } @Override public void onScrollStateChanged(RecyclerView recyclerView, int scrollState) { if(scrollState == RecyclerView.SCROLL_STATE_IDLE) { recyclerView.removeCallbacks(mSettlingResumeRunnable); sPicasso.resumeTag(TAG); } else if(scrollState == RecyclerView.SCROLL_STATE_SETTLING) { mSettlingResumeRunnable = new Runnable() { @Override public void run() { sPicasso.resumeTag(TAG); } }; recyclerView.postDelayed(mSettlingResumeRunnable, SETTLING_DELAY); } else { sPicasso.pauseTag(TAG); } } }
Add the Listener with recyclerView.addOnScrollListener(new PicassoOnScrollListener(context)); – now, when you add .tag(PicassoOnScrollListener.TAG) to your image requests, image loading is paused while users scroll in your RecyclerView.
It’s also convenient to enable logging for debugging purposes. Also, you might want to change the bitmap configuration for low memory devices to RGB_565 to prevent OutOfMemoryError, at the cost of lower image quality. This can be achieved by building a custom Picasso instance in your Application class:
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Picasso.Builder picassoBuilder = new Picasso.Builder(this); if(BuildConfig.DEBUG) { picassoBuilder.loggingEnabled(true); } if(isLowMemoryDevice()) { picassoBuilder.defaultBitmapConfig(Bitmap.Config.RGB_565); } Picasso.setSingletonInstance(picassoBuilder.build()); } private boolean isLowMemoryDevice() { if(Build.VERSION.SDK_INT >= 19) { return ((ActivityManager) getSystemService(ACTIVITY_SERVICE)).isLowRamDevice(); } else { return false; } } }
One comment on “Image Loading with Picasso”