Android Picasso Tutorial

Filed Under: Android

Android Picasso is a powerful image downloading and caching library. In this tutorial, we’ll be discussing and implementing Picasso library in our android application.

Android Picasso

Android Picasso is an image loading/processing library developed and maintained by Square Inc. It’s immensely popular since it often requires just one line of code and has a similar style of coding for each of its features(we’ll be implementing them soon!). To use the android Picasso Library in your Android Studio project, add the following dependency in your build.gradle file.


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

Android Picasso comes with its own set of features such as:

  1. Resizing and Scaling
  2. Center Cropping
  3. Rotation and Transformation
  4. Setting the Placeholder and Error images
  5. Fading
  6. Disk and Memory Caching
  7. Priority Requests
  8. Support for Request cancellation and parallel downloading

Android Picasso – Loading image from URL

To load a image from URL in an ImageView using picasso api, following code snippet is commonly used.


Picasso.with(context).load("http://cdn.journaldev.com/wp-content/uploads/2016/11/android-image-picker-project-structure.png").into(imageView)

Android Picasso – Loading a resource

To load a resource (drawable/mipmap):


Picasso.with(context).load(R.mipmap.ic_launcher).into(imageView);

Android Picasso – Loading image from File

To load a file image :


File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Sample.jpg");

Picasso.with(context).load(file).into(imageView);

Android Picasso Caching

  1. Memory Policy
  2. Picasso by default tries to get an image from the memory first. To prevent this we can add the method noMemoryPolicy() by calling either or both of the enums MemoryPolicy.NO_CAHE, MemoryPolicy.NO_STORE.

    • Memory.NO_CACHE is used to prevent loading the image from the stored cache.
    • Memory.NO_STORE is used to not store the image in the cache at all. Typically used if we need the image one single time.
    
    Picasso.with(context).load(image_url).memoryPolicy(MemoryPolicy.NO_CACHE).into(imageView);
    
    
    Picasso.with(context).load(image_url).memoryPolicy(MemoryPolicy.NO_STORE).into(imageView);
    
  3. Network Policy
  4. If the image is not served/prevented from the Memory, Picasso next tries to get it from the Disk Cache.
    To skip the disk cache we need to call the method .networkPolicy() with the parameter set as NetworkPolicy.NO_CACHE

    Another useful enum is NetworkPolicy.OFFLINE which would check for the image in the cache only. It’ll show the error image(if defined) or blank if the image is not found in the cache.

    
    Picasso.with(context).load(image_url).networkPolicy(NetworkPolicy.NO_CACHE).into(imageView);
    

Let’s dive into the coding part of android picasso tutorial where we’ll see and implement all the features together.

Android Picasso Example Project Structure

android picasso tutorial, android picasso image download example

Android Picasso Example Code

The activity_main.xml is given below.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.journaldev.picassotutorial.MainActivity">

    <Button
        android:text="Drawable"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:id="@+id/btnDrawable" />

    <ImageView
        android:id="@+id/imageView"
        android:src="@mipmap/ic_launcher"
        android:layout_width="200dp"
        android:layout_centerHorizontal="true"
        android:layout_height="200dp" />

    <Button
        android:text="Placeholder"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btnPlaceholder"
        android:layout_alignBaseline="@+id/btnUrl"
        android:layout_alignBottom="@+id/btnUrl"
        android:layout_centerHorizontal="true" />

    <Button
        android:text="URL"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btnUrl"
        android:layout_alignBaseline="@+id/btnDrawable"
        android:layout_alignBottom="@+id/btnDrawable"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

    <Button
        android:text="Error"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btnError"
        android:layout_below="@+id/btnDrawable"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_marginTop="@dimen/activity_horizontal_margin" />

    <Button
        android:text="Callback"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btnCallBack"
        android:layout_alignBaseline="@+id/btnError"
        android:layout_alignBottom="@+id/btnError"
        android:layout_alignLeft="@+id/btnPlaceholder"
        android:layout_alignStart="@+id/btnPlaceholder" />

    <Button
        android:text="Resize"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btnResize"
        android:layout_alignBaseline="@+id/btnCallBack"
        android:layout_alignBottom="@+id/btnCallBack"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

    <Button
        android:text="Rotate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btnError"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_marginTop="13dp"
        android:id="@+id/btnRotate" />

    <Button
        android:text="Scale"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btnScale"
        android:layout_alignLeft="@+id/btnCallBack"
        android:layout_alignStart="@+id/btnCallBack"
        android:layout_alignBottom="@+id/btnTarget" />

    <Button
        android:text="Targets"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btnTarget"
        android:layout_alignBaseline="@+id/btnRotate"
        android:layout_alignBottom="@+id/btnRotate"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />
</RelativeLayout>

The code for MainActivity.java is given below:


package com.journaldev.picassotutorial;

import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    ImageView imageView;
    int i = 0;
    Button btnDrawableImage, btnUrlImage, btnErrorImage, btnPlaceholderImage, btnCallback, btnResizeImage, btnRotateImage, btnScaleImage, btnTarget;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

    }

    private void initView() {

        imageView = (ImageView) findViewById(R.id.imageView);
        btnDrawableImage = (Button) findViewById(R.id.btnDrawable);
        btnUrlImage = (Button) findViewById(R.id.btnUrl);
        btnPlaceholderImage = (Button) findViewById(R.id.btnPlaceholder);
        btnErrorImage = (Button) findViewById(R.id.btnError);
        btnCallback = (Button) findViewById(R.id.btnCallBack);
        btnResizeImage = (Button) findViewById(R.id.btnResize);
        btnRotateImage = (Button) findViewById(R.id.btnRotate);
        btnScaleImage = (Button) findViewById(R.id.btnScale);
        btnTarget = (Button) findViewById(R.id.btnTarget);

        btnDrawableImage.setOnClickListener(this);
        btnPlaceholderImage.setOnClickListener(this);
        btnUrlImage.setOnClickListener(this);
        btnCallback.setOnClickListener(this);
        btnResizeImage.setOnClickListener(this);
        btnErrorImage.setOnClickListener(this);
        btnRotateImage.setOnClickListener(this);
        btnScaleImage.setOnClickListener(this);
        btnTarget.setOnClickListener(this);


    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btnDrawable:
                Picasso.with(this).load(R.drawable.image).into(imageView);
                break;
            case R.id.btnPlaceholder:
                Picasso.with(this).load("www.journaldev.com").placeholder(R.drawable.placeholder).into(imageView);
                break;
            case R.id.btnUrl:
                Picasso.with(this).load("http://cdn.journaldev.com/wp-content/uploads/2017/01/android-constraint-layout-sdk-tool-install.png").placeholder(R.drawable.placeholder).into(imageView);
                break;
            case R.id.btnError:
                Picasso.with(this).load("www.journaldev.com").placeholder(R.drawable.placeholder).error(R.drawable.error).into(imageView);
                break;
            case R.id.btnCallBack:
                Picasso.with(this).load("www.journaldev.com").error(R.mipmap.ic_launcher).into(imageView, new Callback() {
                    @Override
                    public void onSuccess() {
                        Log.d("TAG", "onSuccess");
                    }

                    @Override
                    public void onError() {
                        Toast.makeText(getApplicationContext(), "An error occurred", Toast.LENGTH_SHORT).show();
                    }
                });
                break;
            case R.id.btnResize:
                Picasso.with(this).load(R.drawable.image).resize(200, 200).into(imageView);
                break;
            case R.id.btnRotate:
                Picasso.with(this).load(R.drawable.image).rotate(90f).into(imageView);
                break;
            case R.id.btnScale:

                if (i == 3)
                    i = 0;

                else {
                    if (i == 0) {
                        Picasso.with(this).load(R.drawable.image).fit().into(imageView);
                        Toast.makeText(getApplicationContext(), "Fit", Toast.LENGTH_SHORT).show();
                    } else if (i == 1) {
                        Picasso.with(this).load(R.drawable.image).resize(200, 200).centerCrop().into(imageView);
                        Toast.makeText(getApplicationContext(), "Center Crop", Toast.LENGTH_SHORT).show();
                    } else if (i == 2) {
                        Picasso.with(this).load(R.drawable.image).resize(200, 200).centerInside().into(imageView);
                        Toast.makeText(getApplicationContext(), "Center Inside", Toast.LENGTH_SHORT).show();
                    }
                    i++;
                }
                break;

            case R.id.btnTarget:
                Picasso.with(this).load("http://cdn.journaldev.com/wp-content/uploads/2017/01/android-constraint-layout-sdk-tool-install.png").placeholder(R.drawable.placeholder).error(R.drawable.error).into(target);
                break;
        }
    }

    private Target target = new Target() {
        @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {

            imageView.setImageBitmap(bitmap);
        }

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

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {
            imageView.setImageDrawable(placeHolderDrawable);
        }
    };
}

Essentially in the above code, we’ve implemented a feature of Picasso on each button click.

  1. Drawable : This button click invokes the most basic feature of Picasso i.e. Loading A drawable image into an ImageView
  2. Placeholder : A placeholder is commonly used to display a drawable image while the main image gets loaded into the imageview. This is essential in cases when the image takes time to load from the web.
    
    Picasso.with(this).load("www.journaldev.com").placeholder(R.drawable.placeholder).into(imageView);
    

    A .placeholder() is relevant only after the load method. In the above line, since the URl doesn’t fetch any image, the ImageView stays with the placeholder.

  3. URL: To load an image from a URl, the url is enclosed as a String inside the load() method
  4. Error : An error drawable is generally used in cases where there’s a failure in loading the image. In this case the interim placeholder image gets replaced by the error drawable that’s placed inside .error() method.
  5. Callback : Picasso provides callback methods through which we can keep a check of the status of the image loaded (success/error) and display a text accordingly. We’ve displayed a Toast message for the same when an error occurs as show below.
    
    Picasso.with(this).load("www.journaldev.com").error(R.mipmap.ic_launcher).into(imageView, new Callback() {
                        @Override
                        public void onSuccess() {
                            Log.d("TAG", "onSuccess");
                        }
    
                        @Override
                        public void onError() {
                            Toast.makeText(getApplicationContext(), "An error occurred", Toast.LENGTH_SHORT).show();
                        }
                    });
    
  6. Resize : Picasso allows us to use a resize the image before displaying it in an ImageView by invoking the method resize() and passing the desired width and height in pixels
  7. Rotate : To rotate an image pass the float value inside the rotate() method. The image is rotated in degrees upon it’s anchor point (0,0)
  8. Scale : Resizing an image can cause stretched images. To keep the aspect ratio intact use centerCrop() or centerInside() with the resize() method.
    fit() is like a delayed resize(), that reduces the image to fit the ImageView bounds.
    Note : fit cannot be used with resize() since it has a built-in resize. centerCrop and centerInside can’t be used without calling resize() with a positive width and height
  9. Targets : This is another form of callback that’s used as a listener for image loading. Targets are an interface that would return the bitmap image along with its placeholder and error drawable(if defined). We can further customise the bitmap image returned in the method onBitmapLoaded() or directly show it in the ImageView

The output of the our android picasso example application in action is shown below.

android picasso example

Android Picasso – .noFade() and .noPlaceholder()

Picasso by default fades in the image inside the imageview to provide a meaningful animation. To remove this android animation invoke the method noFade() in the code as :


Picasso.with(this).load().placeholder(R.drawable.placeholder).error(R.drawable.error).noFade().into(imageView);

A noPlaceholder() method is handy when an ImageView handles multiple Picasso calls. Going the conventional way(without noPlaceholder method) would cause every new Picasso call to change the previous image to the placeholder and then to the new image. This can look ugly and this is where noPlaceholder() comes to our rescue.

Android Picasso – Resuming/Pausing/Cancelling Requests

To do any of the above, we need to first set a tag as :


Picasso.with(this).load().tag("Me").into(imageView);

Resuming, Pausing or Cancelling a request is generally done in ListView/RecyclerView.


Picasso.with(this).resumeTag("Me");
Picasso.with(this).pauseTag("Me");
Picasso.with(this).cancelTag("Me");
Picasso.with(this).cancelRequest(imageView); //alternative

Android Picasso Priority Requests

A request such as the one below has higher chances of getting completed first in a ListView which many multiple requests.


Picasso.with(this).load().priority(HIGH).into(imageView);

priority() offers three types of Constants : HIGH, NORMAL and LOW

Note: Setting a priority just gives an intended order of request calls. It doesn’t gurantee to strictly follow the order.

This brings an end to android picasso tutorial. You can download the final Android Picasso example project from the link given below.

Comments

  1. Tushar Bhad says:

    this tutorial is just awesome….keep it up…

  2. sakhi says:

    can you please help to resolve this error while using .load (cannot resolve into(android.widget.imageview))

    1. Anupam says:

      Try using Picasso.get()……..

  3. Joseph Aguele says:

    oh thanks so much bro, this tutorial is highly appreciated

  4. ayoub says:

    some image dont loading like jpg

  5. Praneeth says:

    Can You Suggest for the Updated dependency which has get(), instead of with(), I’m not able to proceed as the image is not loading

    1. Anupam says:

      Picasso.get().load(“url_string”).into(imageView);

    2. JM says:

      Make sure your Internet Permission is in place. Manifest File.

  6. abhinesh says:

    how to load image from Drawable folder dynamically

    1. Anupam says:

      Hi Abhinesh,
      The drawable folder typically contains static images. Can you specify what does it mean by dynamic from the drawable folder?

  7. Louis ryan says:

    Great article about android picasso tutorial.. You seem to have a good understanding about it.It’s impressive and also helped too.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages