Android Image Loading from a String URL
Occasionally, adding images to your android application is simple and straightforward, and all you have to do is place the image in the drawable folder and set the ImageView source (“src”) property in your layout xml file to the correct path.
Things get a bit trickier when you need to pull the image from a URL, often just provided as a string variable. For example, let’s say you are building a news app that pulls current headlines from a news API. Once you parse the JSON data in your app, you will have a string variable with the URL to the image. You may, at this point, be asking yourself, how can you use that string variable to pull the image from the URL and add it to your app? If so you’ve come to the right place, read on to find out how.
Two Paths, One Goal (with a Clear Winner)
I’m sure there are multiple ways to accomplish this task of loading images into your android app from a URL, but I am going to cover two that have worked for me. The first is a do-it-yourself method that involves creating an AsyncTask inner class in your Adapter (e.g. RecyclerView.Adapter or ArrayAdapter) to grab and pass in the Bitmap image. The second uses an external library called Picasso. Note, Picasso is not the only library option available for loading images. Glide and Fresco are two other popular image loading libraries, but since they are both implemented in a similar manner to Picasso, I will not cover them here. Once you learn how to use Picasso, figuring out Glide or Fresco should be a breeze.
I have to admit, I was tempted to not discuss the first do-it-yourself path after trying Picasso because Picasso was so much easier to implement. It also provides a significant performance advantage. But I decided to include the steps to create your own loader because it’s pretty straightforward and I found it helpful in order to better understand how the process works. I personally had a tough time figuring out how to get this functionality to work properly when I was first trying to accomplish this task. Google was not my friend and it took a fair amount of fruitless searching to find a working solution. This is the article I wish I had found when I was trying to figure this out, and I hope it helps save you, dear reader, some of your precious time.
Let’s say you have your RecyclerView.Adapter class all set up and it’s correctly updating your views with the exception of the ImageView. In order to grab that image from the URL, which you can currently only access as a string variable through the adapter, it’s easiest to create a loader inner class that extends AsyncTask. The reason you’ll want to accomplish this task asynchronously is so you don’t lock up your app on the user while it is downloading each of the images.
When you instantiate this AsyncTask class you will pass in the ImageView to the class, and the string url to the execute method (see code below). Note I wrapped the instantiation in an “if” statement to avoid a null pointer exception if for some reason the url string is null.
Then inside the AsyncTask doInBackground method you need to:
· create a Bitmap variable
· open an InputStream with the url that was passed in
· use BitmapFactory.decodeStream() on the InputStream
· assign it to the created Bitmap variable.
Then in the onPostExecute method, you simply use setImageBitmap on the ImageView object to add the image, as you can see below.
You should now see the images load into your app when you run it, woohoo! Now that you’ve figured out how to load web images into your app on your own, let’s take a look at a faster and easier way.
Picasso to the Rescue
If you implemented the above method for adding images to your app you may have noticed they load rather slowly, especially if you are loading a lot of images at once. It shouldn’t cause your app to freeze up or anything since we used an AsyncTask, but it can be annoying for your end user who is waiting for them all to load. I wanted better performance and found it in Picasso, a library created by Square that is simple to implement. Below are some of the reasons for this improvement in performance:
· Handles ImageView recycling and download cancelation in an adapter
· Complex image transformations with minimal memory use
· Automatic memory and disk caching
So what do you need to do to start using Picasso? The first step is to add it to your gradle or maven dependencies.
Then all you need is one line of code to start using Picasso!
The elements that need to be passed in are the context, the string variable with the URL, and the ImageView that it is updating. There are also a number of other optional parameters you can pass in to do different things, such as resizing the image, adding a placeholder image, defining how it is cropped, or adding an error image.
You can even customize transformations by creating a new class that implements Transformation. You can see in the above example that I instantiated a customized transformation class called CircleTransform. Here is the implementation of my CircleTransform class:
In my CircleTransform class, I rounded the edges of the image and added a margin. Those are passed into the class when it is instantiated. You can check out the final result below in the CNews app, a sample news aggregator I built.
As you can see, Picasso is simple to implement. If you followed along and tried both of the methods I covered, you likely noticed how Picasso provides a significant performance boost as well. You can check out the Picasso documentation for more info about the library and available customizations.
I hope this was a helpful explanation of how to load images into your app based on a string URL. Now you know how to complete this task in two ways, by creating your own asynchronous loading class, and by using the external library Picasso. Although Picasso is quick and easy to implement and provides a nice boost in performance, I believe it’s still helpful to understand how you can accomplish this task on your own, without the help of an external library.
About the Author
I'm a clinical psychologist, informaticist, developer, crypto-enthusiast, and incurable tech junkie.