Hassle-Free Image Loading in Android with Picasso from Square

Theodhor Pandeli
Share

Images add flavor, character and delight to your app interfaces. Image loading in Android typically involves adding many lines of code boilerplate code. Picasso from Square is one of the simplest libraries to use and includes memory and data optimization, allowing you to choose not to save the images in cache after they are downloaded.

In this tutorial I will show how to download images from external locations, using a file path, image resource id or any URI in your Android application using Picasso.

You can find the project on GitHub. You can download the drawables used in the project here, make sure you add them to the drawables folder.

Sample application screenshot

Adding Picasso to Your Project

Note: I am using version 2.5.2 of Picasso.

Create a new Project in Android Studio and add this line inside dependencies in build.gradle (Module: app):

compile 'com.squareup.picasso:picasso:2.5.2'

Sync Gradle in your project to download the library.

Add the internet permission in AndroidManifest.xml.

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

In this project I am going to use a single activity class and layout resource file.

XML Layout

The interface of this sample application includes three ImageViews, inside a vertical-oriented linear layout. Each image will be downloaded, saved and displayed using a different method of the library.

The code for activity_main.xml is below (don’t forget to change to your package name):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.theodhor.picasso.MainActivity">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:id="@+id/activity_main"
        android:layout_centerHorizontal="true">

        <ImageView
            android:layout_width="150dp"
            android:layout_height="150dp"
            android:layout_gravity="center_horizontal"
            android:id="@+id/image_1"
            android:layout_margin="5dp"/>

        <ImageView
            android:layout_width="150dp"
            android:layout_height="150dp"
            android:layout_gravity="center_horizontal"
            android:id="@+id/image_2"
            android:layout_margin="5dp"/>

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/image_3"
            android:layout_margin="5dp"/>

    </LinearLayout>

</RelativeLayout>

Displaying Images

The first step is creating a reference in your Java code for each of the above ImageViews. Add the following below the MainActivity class declaration:

ImageView firstImage, secondImage, thirdImage;

Below this code, create String variables and give them the value of any image URI. Since you are using three ImageViews, an URI for each is needed:

private static final String IMAGE_1 =
"http://uxmastery.com/wp-content/uploads/2015/06/sitepoint-logo-195x195.jpg";
private static final String IMAGE_2 =
"http://uxmastery.com/wp-content/uploads/2015/06/sitepoint-logo-195x195.jpg";
private static final String IMAGE_3 =
"https://www.sitepoint.com/premium/books/git-fundamentals/online/images/sitepoint-logo-2012.png";

Inside the onCreate() method, create the references for the ImageViews:

firstImage = (ImageView)findViewById(R.id.image_1);
secondImage = (ImageView)findViewById(R.id.image_2);
thirdImage = (ImageView)findViewById(R.id.image_3);

The simplest way to download an image, save it in device memory and display it is with this line of code, added below the image references:

Picasso.with(this).load(IMAGE_1).centerCrop().fit().into(firstImage);

You need to reference each instance of Picasso inside the application context, using with(context). Then .load(parameter) can accept a file, resource id, path or uri of any image as a parameter. .centerCrop() places the image in the center of the ImageView and uses .fit() to stretch the image according to the ImageView size. You can also use .resize(int width, int height) to set the explicit size of the downloaded image. The last method, .into(parameter), accepts the ImageView to display the image as a parameter.

This was the shortest line of code for displaying an image from an external source.

This is the shortest line of code to load an image, but Picasso lets you use different methods to better use network data, device memory and processor.

A more customized example to do the same is:

Picasso.with(this)
  .load(IMAGE_1)
  .centerCrop()
  .fit()                    .placeholder(getResources().getDrawable(R.drawable.placeholder,null))
  .error(getResources().getDrawable(R.drawable.no_image,null))
  .rotate(45)
  .memoryPolicy(MemoryPolicy.NO_CACHE)
  .priority(Picasso.Priority.HIGH)
  .into(firstImage);

With larger images, you can use a placeholder which displays a dummy image until the desired one has downloaded and ready to display. You can use the same technique to avoid empty ImageViews when loading encounters an error.

By skipping Cache, Picasso avoids cache look up while processing a request. This can apply in cases when you are sure that the image cannot be found in cache. Use .memoryPolicy(MemoryPolicy.NO_STORE) to not store the image in cache after it has downloaded.

Each image can have its own Priority: LOW, NORMAL or HIGH.

You are going to display the secondImage using a Target which has three main methods to determine the status of the image downloading process. Add this code after the previous Picasso calls:

Target target = new Target() {
   @Override
   public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
          secondImage.setImageBitmap(bitmap);
   }

   @Override
   public void onBitmapFailed(Drawable errorDrawable) {
          secondImage.setImageDrawable(errorDrawable);
   }

   @Override
   public void onPrepareLoad(Drawable placeHolderDrawable) {                secondImage.setImageDrawable(getResources().getDrawable(R.drawable.prepare_load,null));
   }
};    

target.onBitmapFailed(getResources().getDrawable(R.drawable.no_image,null));

Picasso.with(this).load(IMAGE_2).priority(Picasso.Priority.HIGH).into(target);

The overridden methods of the Target allow you to better manage the process. You can set the parameters of these methods by calling them from outside of the target. You can set the bitmap displayed when downloading fails using:

target.onBitmapFailed(getResources().getDrawable(R.drawable.no_image,null));

The next line creates an instance of Picasso, downloading the image located at IMAGE_2.

You will download the third image using a ‘Picasso Builder’. This will help distinguish where this image comes from. If the image is found in device memory or disk, Picasso won’t download it but use the currently available one. By creating a Builder, you can display Debug Indicators that show the image source.

Picasso source debug indicators

The builder supports another method, called when an image load fails.

//Third method
Picasso.Builder picassoBuilder = new Picasso.Builder(this);
picassoBuilder.listener(new Picasso.Listener() {
    @Override
    public void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception) {
        Log.e("TAG","Failed");
    }
});
Picasso picasso = picassoBuilder.build();
picasso.setLoggingEnabled(true);
picasso.setIndicatorsEnabled(true);
picasso.load(IMAGE_3).centerCrop().resize(400,100).placeholder(R.drawable.no_image).into(thirdImage);

This time you are creating an instance of Picasso using the Builder. As this image is wide, you need to resize the image to keep the correct ratio. A placeholder can be a good element for the application user interface because we can never predict the connection speed and time required to download each image.

Conclusion

In this tutorial I showed you how easy the Picasso library is to configure and use allowing you to download, display and format images in a few lines of code.

I hope you find it as easy to use as I do and if you have any comments or questions, please let me know below.