Blog

Efficient Image Loading in Android

In this post I am going to discuss about how to efficiently work with images in android without impacting performance/speed of application. I will be using a popular image loading library called Picasso.

What I will discuss/Implement:
1) How to load many images (from web or phone’s memory) efficiently in a single activity (just like profile images in whatsApp chat screen).
2) Crop square/rectangular images to make circular thumbnails.

Picasso:
Picasso is open source, powerful image download and caching library for Android. It is created and maintained by Square.

http://square.github.io/picasso/

https://github.com/square/picasso

Advantages:
1) It simplifies the process of loading images from external urls and display in application. Downloading an image from external urls needs larger amount of code to achieve this via android networking API’s. But by using Picasso, it can be achieve with few lines of code.
2) While working with many images, implementing image caching logic in order to provide a seamless user experience is necessity. Picasso provides automatic image caching.
3) Provides methods for custom transformation (eg circular) for more advance effects. Image transformation is very memory costly in android leading to OutOfMemoryException. Picasso deals with all this.
4) Provides methods for resizes images to better fit into layouts and to reduce memory size.

Installation:
If using eclipse as development IDE, then download picasso-2.4.0.jar from http://square.github.io/picasso/ into application lib folder.
If using Android Studio IDE, then add below dependency in build.gradle file of project.

 dependencies {
 ………
 compile ‘com.squareup.picasso:2.5.2’
 ………
 }

Example :
1) Create a new project in Eclipse or Android Studio. While doing so, choose blank activity.
2) Open the layout file for main activity and add following ImageView to the layout.

3) Navigate to MainActivity file and add following lines of code in onCreate method.

     ImageView imageView = (ImageView) findViewById(R.id.imageView);
     Picasso.with(context)
                 .load(url")
                 .into(imageView);

In the first line, we get a reference to the ImageView instance in the layout file. We then load an image into the image view using the Picasso library. We first specify the context by calling with() and passing in the context. We then call the load() method and supply in it with the location of the image. Finally, we tell Picasso where it should display the image when it’s fetched by calling into() and pass in the imageView object.

Load() method support resources, URL, and files as image sources

       Picasso.with(context).load(R.drawable.carImage).into(imageView);
       Picasso.with(context).load(Web URL).into(imageView);
       Picasso.with(context).load(new File(image_path)).into(imageView);

Placeholder and Error Fallback:
For any real time application, we must think of all possible cases. Picasso provide placeholder and error fallback for ImageView. Placeholder is an image that will be shown before the image is loaded. Error fallback will be shown if, there is an error while downloading/loading image. Both fallback and placeholder are optional.

           Picasso.with(this)
                       .load(URL)
                       .placeholder(R.drawable.placeholder_image); // optional
                       .error(R.drawable.fallback_image)         // optional
                       .into(imageView);

Image Resize and rotating:
Picasso offers resizeDimen() and rotate() for resizing image to the size of ImageView while maintain aspect ratio and rotating.

          Picasso.with(this)
                      .load(URL)
                      .placeholder(R.drawable.placeholder_image) 			// optional
                      .error(R.drawable.fallback_image)        				 // optional
                      .resizeDimen(R.dimen.image_width, R.dimen.image_height)	// optional
                      .rotate(90)								// optional
                      .into(imageView);

Transformations:
Custom transformation on images can be done using Bitmaps in android. But bitmaps are very memory consuming and slow down application specially when a lot of images needs to be loaded in a single activity. This forces us to implement memory caching and lazy loading technique leading to lots of code writing.
Picasso provide transform() function in which we can pass custom transformation to be applied on images. Here I am going transform a rectangular image into circular thumbnail (many applications use circular image for showing profile pictures like whatsapp , viber).
centreCrop() crop the image from its centre.

    Picasso.with(this)
                .load(URL)
                .placeholder(R.drawable.placeholder_image) 	// optional
                .error(R.drawable.fallback_image)        		// optional
                .transform(new RoundedTransformation(R.dimen.radius, R.dimen.margin))	// optional
                .resizeDimen(R.dimen.image_width, R.dimen. image_height)			// optional
                .centerCrop()									// optional
                .into(imageView);

In RoundedTransformation() value of radius should be more than half the size of image width or height (whichever is smaller).
Add following file in project’s src package. This RoundedTransformation.java contain code for rounded transformation.

 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.RectF;
 import android.graphics.Shader;
 public class RoundedTransformation implements com.squareup.picasso.Transformation {
 private final int radius;
 private final int margin;  

 public RoundedTransformation(final int radius, final int margin) {
    this.radius = radius;
    this.margin = margin;
 }

 @Override
 public Bitmap transform(final Bitmap source) {
    final Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setShader(new BitmapShader(source,  Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
    Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(output);
    canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() - margin, source.getHeight() - margin), radius, radius, paint);

    if (source != output) {
        source.recycle();
    }
     return output;
 }
 @Override
  public String key() {
    return "rounded";
  }

}
These transformations will occur in the same background thread used to decode the original source bitmap and the final result will be stored into memory. This means you can store different transformations of the same source bitmap for future use.

4) Add Internet permission
Add following line in manifest file of project.

< uses-permission android:name="android.permission.INTERNET" />

5) Finally build and run project.

By – Shalabh Tripathi, Developer

adminEfficient Image Loading in Android
Share this post

Join the conversation

Related Posts