Decoding Picasso library- one image at a time.

Anshul Jain
MindOrks
Published in
5 min readJan 9, 2018

So how does one of the most used Android Image library work internally?

The above diagram can be a little overwhelming at first. So let’s try to understand it in more detail.

I will be explaining the important classes in the Library with their major responsibilities. It would be helpful if Picasso code is checked out and opened in Android Studio, so that the article becomes easy to understand.

Picasso Components:

One simple statement like this loads an image url into an ImageView.

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

Now let us break the above statement into the multiple statements and analyze them one by one.

Picasso picasso = Picasso.with(context);

To carry out basic image loading operations, we first need to interact with the Picasso object which is a singleton. Let’s take a look at how this object is built.

The Picasso object is created of many components like downloader, cache, executor, transformer etc. We can provide custom implementations of these components. If not provided, then Picasso will pick up their default implementation. Let us take a closer look at these components.

ExecutorService
Picasso is handling multiple image requests through an executor. The default implementation has the following responsibilities.

  • Adjusting the number of threads based on the network type. The default implementation has between 1(2g) to 4(Wi-Fi) threads. Check out the code at PicassoExecutorService.java to know more.
  • The executor will pick up the image load task based on its priority. In its default implementation, picasso supports only three types of priorities- LOW, NORMAL and HIGH. Higher priority tasks get picked up first.
  • If two tasks have same priority, then the request will be picked up based on the order in which it came i.e. FIFO ordering.

Cache
Picasso uses LruCache class for providing in-memory caching implementation. This class allocates max cache size to approximately 15% of the total allocated app heap size. This cache is used to store Bitmaps of the loaded images.

Downloader
The main responsibility of this class is to implement load() function which takes okhttp3.Request as an input and returns okhttp3.Response as the output. This class also takes care of the disk cache. A custom downloader can be used in scenarios where we need to have request connection time which is different from the default connection time.

RequestTransformer
According to the Picasso documentation, this class is called immediately before every request is submitted. This can be used to modify any information about a request. For example, if you use a CDN you can change the hostname for the image based on the current location of the user in order to get faster download speeds.

Loading of an Image:

Once we get an instance of Picasso, we now try to load an image url into an ImageView/Target. We do so with the help of RequestCreator.java.

RequestCreator
With the help of this class we start to load the image in the ImageView. This class takes in a whole lot of other properties for loading the image like:

memoryPolicy - Specifies whether to look up the memory cache while loading an image. Also whether to store the image in memory cache or not.

networkPolicy - Specifies whether to look up the disk cache while loading an image. Also whether to store the image in the disk cache or not once the image download is successful. One can also provide a network policy as OFFLINE, so that the image is taken up from the disk cache only and not from the network.

tag- A tag associated with an image which can be later used to pause/cancel the image download. Same tag can be associated with multiple requests.

errorDrawable - If the image download fails to download, then put this drawable into the imageView.

placeHolderDrawable - Till the image download happens, put this drawable as a placeholder into the imageView

As soon as the into() function is called on the RequestCreator object, an Action object is created out of it. Every Action object has a request key. This object is then dispatched to Dispatcher.java.

Dispatcher
This class contains an instance of HandlerThread which listens to various types of messages like REQUEST_SUBMIT, REQUEST_CANCEL, TAG_PAUSE, TAG_RESUME etc.

This class stores all the request keys in a Map. If the key is not found in the map, then the dispatcher creates a BitmapHunter(Runnable) object and submits to the PicassoExecutorService. If the key is already present, then it attaches the Target(ImageView) with the BitmapHunter.

BitmapHunter
This class extends Runnable and runs on the executor. The main responsibilities of this are:

  • Return the bitmap from the memory cache if the key is already present in the cache.
  • If the key is not present in memory cache, then it asks the NetworkRequestHandler to give back the image stream.
  • Once it gets back the result from the NetworkRequestHandler, this class decodes the stream to bitmap and stores the bitmap in the memory cache.
  • This class also dispatches the result to the Dispatcher with a message HUNTER_COMPLETE or HUNTER_DECODE_FAILED based on whether the image download succeeded or failed. The Dispatcher.java class in return passes on the result to Picasso.java which finally updates the UI.

NetworkRequestHandler:
This class does the following things:

  • Return the image stream from the disk cache if the key is already present in the cache.
  • If the key is not present in the disk cache, then the downloader initiates a network request.
  • Once the network request is successful, the downloader stores the image stream in the disk cache and passes on the result to the BitmapHunter class.

Cancellation and Retry of Image Request

Cancellation of Image Request can be done by passing the tag or the ImageView object itself. If multiple requests have the same tag, then all of them will be cancelled. After cancellation of an image request, Picasso makes sure that the image is not loaded on the ImageView, even if the image gets downloaded.

If the image fails to load from network because of no internet, then upon getting the network back, the image retries for download. The number of such retries are 2.

Thanks for reading out the article. Let me know if I have missed out something interesting so that I can be added.

Check out my other Github projects here and my other medium articles here. Also, let’s get connected on LinkedIn.

--

--

Anshul Jain
MindOrks

ex Android Developer | Machine Learning Developer @ Dailyhunt