Donn Felker

Not A Subscriber?

Join thousands of people who build and refuse to get left behind. One message a week on building, using AI as an accelerator, and staying sharp in the new AI frontier.

Receive one free message a week

August 15, 2013 Donn Felker

Loading Remote Images in Android with UrlImageView

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: 

PicassoSample.java

Picasso.with(getContext()).load("http://path/to/some/file.png").into(myImageView);

View on GitHub

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:

UrlImageView.java

package com.donnfelker.view;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.donnfelker.android.R;
import com.donnfelker.app.BootstrapApplication;
import com.squareup.picasso.Picasso;
import javax.inject.Inject;
public class UrlImageView extends ImageView
{
@Inject Picasso picasso;
private int defaultImageId = R.drawable.ic_placeholder;
private String url;
public UrlImageView(final Context context)
{
this(context, null);
}
public UrlImageView(final Context context, final AttributeSet attrs)
{
this(context, attrs, 0);
}
public UrlImageView(final Context context, final AttributeSet attrs, final int defStyle)
{
super(context, attrs, defStyle);
BootstrapApplication.getInstance().inject(this);
}
public String getUrl() {
return url;
}
public int getDefaultImageId()
{
return defaultImageId;
}
public void setDefaultImageId(final int defaultImageId)
{
this.defaultImageId = defaultImageId;
}
public void setUrl(final String url)
{
this.url = url;
picasso.load(getUrl()).placeholder(getDefaultImageId()).into(this);
}
}

View on GitHub

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. 🙂

FunActivity.java

public class FunActivity extends FragmentActivity {
@Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// ... other stuff, get data model,etc
// We'll call the data model "UserModel" in this example
UrlImageView avatar = (UrlImageView) findViewById(R.id.user_avatar);
// Load the Remote Image into the URL, thats it!
avatar.setUrl(userModel.getAvatarUrl());
}
}

View on GitHub

So how did I inject Picasso? Easy. With a simple @Provides annotation in our Dagger module as shown below.

BootstrapModule.java

import dagger.Module;
import dagger.Provides;
@Module
(
complete = false
)
public class BootstrapModule {
@Provides
Picasso providesPicasso(Context context) {
return Picasso.with(context);
}
}

View on GitHub

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.