How to Load Images from a URL Using Picasso

From WikiHTP

What are the primary features of a mobile application worthy of the name? What all our Android apps are supposed to have mastered, but which are not present in the base of the Google SDK?

Do not look far, I'm talking about network calls and more precisely, viewing an image from a URL. From a user point of view this feature seems simple, especially when one is used to using web technologies like HTML, but in Android, this simple feature breaks down into several actions to perform:

  • Downloading the image asynchronously from a URL
  • Cache management of an image
  • Reducing the size of an image
  • Inserting the image into an ImageView

To have already tried to reproduce all his actions by hand and get a fluid result while keeping a clean code... I can only advise you to turn to bookstores that will certainly do a thousand times better than you 😀.

There are several bookshops that chew you work, among them I will tell you about my favourite: Picasso.

Picasso is a popular library of mobile developers for its ease of use, but especially its performance. Let's look at how this module works.

How to use Picasso[edit]

First of all, it is necessary to import it into our project, preferably by using Gradle (I invite you to follow the Introduction to Gradle tutorial if you are not used to the tool). To do this, simply add the following line to your dependencies:

implementation 'com.squareup.picasso:picasso:2.71828'

Once this library is imported, let's look at how to use it. One of the strong points of this library is that it is used directly with ImageViews, no need to modify your layout by adding custom objects to make it work.

Let's take the following view as an example:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:src="#AAA"
        />
 
</RelativeLayout>

With Picasso everything is done on the Java side, let's look at a simple example of use, the one provided on the site of the square:

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

Admit it looks easy to use, just give Picasso an URL and an ImageView, and he does all the work for us 😀.

So let's put this code in our main activity:

public class MainActivity extends ActionBarActivity {
 
    ImageView imageView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.imageView);
 
        Picasso.with(getBaseContext()).load("http://i.imgur.com/DvpvklR.png").into(imageView);
   }
}

Compile and launch the project on your smartphone. Oh, do not you do anything?

Wait, did I tell you that this library was about downloading images and managing the cache for us? Well, we must give him the rights, add to the project the necessary permissions to access the internet and save the images on the SD card:

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

These lines are to be added to our AndroidManifest.xml file :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tutosandroidfrance.picassosample" >
 
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
 
        </activity>
 
    </application>
 
</manifest>

Recompile, everything should work as expected:

The image is downloaded, cached and inserted into the ImageView. If you do not trust me when I tell you that it is well cached, switch your smartphone to airplane mode and restart the application, the image will load well.

Personalization[edit]

The main difference Picasso has with other caching libraries is the freedom to personalize the received images that they offer. Once the image is downloaded and cached, Picasso offers the possibility to modify it before displaying it in the ImageView, which allows, for example, to download an image, apply a blur effect, and then place it as the background of our home screen. These customizations are done through objects named Transformation, and the most magical in all this, Picasso re-hides the transformed image, so that the transformation is performed only once, which greatly improves performances.

Let's just look at how to apply a blur effect on the previously displayed image:

For my blur algorithm I will use pre-existing and very efficient code (thanks to the developer PomepuyN for putting this open-source class):

public class MainActivity extends ActionBarActivity {
 
    ImageView imageView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        imageView = (ImageView) findViewById(R.id.imageView);
 
        Picasso.with(getBaseContext()).load("http://i.imgur.com/DvpvklR.png")
                .transform(new BlurTransformation(this))
                .into(imageView);
    }
 
    public class BlurTransformation implements Transformation {
        private Context context;
 
        public BlurTransformation(Context context) {
            this.context = context;
        }
 
        @Override
        public Bitmap transform(Bitmap source) {
            //Source from : https://raw.githubusercontent.com/PomepuyN/BlurEffectForAndroidDesign/master/BlurEffect/src/com/npi/blureffect/Blur.java
            //Copyright : PomepuyN
            Bitmap result = Blur.fastblur(context,source,10);
 
            if (result != source) {
                source.recycle();
            }
            return result;
        }
 
        @Override
        public String key() {
            return "BlurTransformation";
        }
    }
}

It is possible to add several transformations to an image, like this: (the GrayScaleTransformation is not implemented, it is just given as an example name)

Picasso.with(getBaseContext()).load("http://i.imgur.com/DvpvklR.png")
.transform(new BlurTransformation(this))
.transform(new GrayScaleTransformation()) 
.into(imageView);

Performances[edit]

What you should be wary of every time you use an image processing library is the memory, physical or RAM occupancy. Asking for an image of 3000 × 3000 px does not take the same time as displaying an image 400 × 400 px and above all, you can quickly reach the OutOfMemoryException using large images. That's why I advise you to always resize your images after downloading them. Said like that the operation seems complicated, but the developers of Square have thought of everything, they provide us with several methods to achieve this operation, so I will list them:

Use a Transformation

public class ResizeTransformation implements Transformation{
 
    private int targetWidth;
 
    public ResizeTransformation(int width) {
        this.targetWidth = width;
    }
 
    @Override
    public Bitmap transform(Bitmap source) {
        double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
        int targetHeight = (int) (targetWidth * aspectRatio);
        Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
        if (result != source) {
            // Same bitmap is returned if sizes are the same
            source.recycle();
        }
        return result;
    }
 
    @Override
    public String key() {
        return "ResizeTransformation"+targetWidth;
    }
}

I voluntarily put a small resolution for the effect to be visible. The use of this transformation is simple:

Picasso.with(getBaseContext()).load("http://i.imgur.com/DvpvklR.png")
                .transform(new ResizeTransformation(50))
                .into(imageView);

Use the Resize () method[edit]

Picasso provides a resize method, taking 2 parameters: height and width, which is rather efficient and easy to use, I let you judge:

Picasso.with(getBaseContext()).load("http://i.imgur.com/DvpvklR.png")
                .resize(50,50)
                .into(imageView);

We can notice that the image is now square, I intentionally put 50 × 50 px in order to highlight this concern, this method does not reduce keeping the proportions. In order to use this method, it is necessary to know in advance the ration of the image to be placed (ex: 16/9 or 1/1).

Use the fit() method[edit]

Picasso provides the miracle solution: reduce the image according to the size of the ImageView! yes, it is possible, this method will wait until the ImageView has acquired its size and then will resize the downloaded image while keeping its proportions. To do this, use the .fit () method, which is associated with the .centerInside () method if you want to display the entire image, or .centerCrop () to split the image and fill the ImageView.

CenterInside:

Picasso.with(getBaseContext()).load("http://i.imgur.com/DvpvklR.png")
                .fit().centerInside()
                .into(imageView);

CenterCrop:

Picasso.with(getBaseContext()).load("http://i.imgur.com/DvpvklR.png")
                .fit().centerCrop()
                .into(imageView);

This method is by far my favourite because it is easier to use, more efficient and less expensive in memory. In addition, it avoids degrading the image, in the two previous methods we had to write the precise size in pixels while it adjusts the image directly according to the area displayed, it will be sharper.

.fit () is more than recommended by Jake Wharton 😉.

You can find all my resources at the following address: GitHub

And a lot of additional information about Picasso on their official website:

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

About This Tutorial

This page was last edited on 31 January 2019, at 18:48.