As an Android consultant, I find myself needing to load remote images into an ImageView quite often. Doing this with the Picasso library is quite easy as you simply need to tell the library where the image is located and what ImageView to load the image into. At that point everything else is taken care of for you, including caching (thanks Square Engineering team!) This is great! The code to do this looks like this:ย
However, I have a problem with this approach. As time progresses you’ll have various different Picasso instantiations all over your code base when you need to load up a new image. This can be easily solved with the Dagger Dependency Injection container and a custom ImageView that I call UrlImageView. This file is shown below:
The UrlImageView.java file is simply an ImageView that has been extended to add a couple of additional methods. The method that we care about in this example is setUrl(). When this method is called, a url is passed into the class and then the injected Picasso instance loads that image located at that URL into into the ImageView (this). During the load, a placeholder is shown. This is the defaultImageId that is a private variable. The placeholder is a drawable file that you use.
Once the file is downloaded, its cached, etc. This depends on how you’ve configured the injected instance of Picasso.
To use this class, simply find the view in your Activity and call setUrl() it as shown below. Everything else is handled for you. ๐
So how did I inject Picasso? Easy. With a simple @Provides annotation in our Dagger module as shown below.
Dagger will create the Picasso instance here and each place that I @Inject Picasso this same set up will be used. This has some benefits. Using Dagger I can create different Picasso instances with the @Named attribute (or by extending Picasso). An example of this would be a simple image loader as we’ve done above. The second example would allow me to create a RoundPicasso provider that renders circle images (think Google+ avatars). You would set up Picasso the same as before but you would also call the transform() method and provide a custom implementation of the Transformation interface that renders the image as a circle.
As you can see, its easy to extend an ImageView with very little code to load remote images. I hope this has helped you develop Android applications faster and more effectively.
kenyee says
In UrlImageView, why not do just this instead of doing the injection? UrlImageView needs to be created w/ a context reference already. And Picasso seems to have static methods you can call directly w/o needing injection…
Picasso.with(getContext()).load(getUrl()).placeholder(getDefaultImageId()).into(this);
Donn Felker says
You can do this and there is nothing stopping you and if it works for you, feel free. I inject Picasso because there are other areas that I use Picasso that are not ImageView related and I want to make sure I’m using the same configuration across each instantiation. This saves on code duplication throughout the application.
BUT if you ONLY need it in ONE place in your app, then your proposed method of implementation is completely acceptable.
Jeff Potter says
Thanks for this post!
samitny says
You don’t need Dependency Injection (or “DI”) to have a single instance of Picasso or any other object.
Personally, I’ve been using the concept of DI for many years mainly because it allowed me to write better code without too much extra code. To be more specific, I was referring to the concept of “Inversion of Control” (or “IoC”).
By following the concept IoC, you write code that’s less coupled. The perfect example of coupled-code is “Codeigniter” (at least when I used to use it), all classes/libraries had references to other parts of the framework, making it impossible to extract and use outside the framework without extensive modification.
A common practice of IoC is to provide an object with all the references it needs, however, the downside is that you have to create many objects, keep their references, etc.
DI simply manages all those objects for you.
Actually, many DI implementations go beyond just providing dependencies, they allow contextual dependencies lookup (think “mockups” for unit-tests), scope-based Instantiation and many other features.
So even though DI isn’t needed to keep however many Picasso references you want, it definitely an elegant and productive way to manage it.
Last but not least, thank you for writing this post, it’s simple and clear!