android-google-volley-imageloader

Setting up the Android Google Volley ImageLoader for NetworkImageView

on October 8, 2013 by Android, Mobile Application Development with 23 comments

Google Volley is awesome. If you’re an Android developer and you’ve done AsyncTask and HttpClient stuff (and there is no avoiding it), prepare for a huge relief once you get up and running with Volley. All of the leg work has been handled for you when it comes to managing the threads, dealing with a JSON response, handling errors, and way more.

Using NetworkImageView

Included with the library is an extremely useful object called NetworkImageView. NetworkImageView is meant to be a direct replacement for the standard ImageView in scenarios when your image resource is coming from a network location (i.e. URL) rather than a static resource. In your layout file, it’s as simple as changing the element from ImageView to NetworkImageView, for example:

    <ImageView
        android:id="@+id/twitter_avatar"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="6dip"
     />

Becomes

    <com.android.volley.toolbox.NetworkImageView
        android:id="@+id/twitter_avatar"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="6dip"
     />

The next step is to populate your element programatically using the URL of the image. This is straight forward as well, at least at first glance:

    NetworkImageView avatar = (NetworkImageView)view.findViewById(R.id.twitter_avatar);
    avatar.setImageUrl("http://someurl.com/image.png",mImageLoader);

And that’s where just about every example on the web leaves it. But what about that mImageLoader variable?

Setting up the ImageLoader

It’s more complicated than it appears. The ImageLoader class is actually responsible for setting up caching on the device, and initializing the object isn’t trivial. To get going with the ImageLoader, start by declaring private variables for use in your class:

private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;

Then in your constructor or OnCreate() method, initialize the objects using the following:

        mRequestQueue = Volley.newRequestQueue(context);
        mImageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {
            private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(10);
            public void putBitmap(String url, Bitmap bitmap) {
                mCache.put(url, bitmap);
            }
            public Bitmap getBitmap(String url) {
                return mCache.get(url);
            }
        });

Now you’re free to use the magical NetworkImageView.setImageUrl() method as intended:

    NetworkImageView avatar = (NetworkImageView)view.findViewById(R.id.twitter_avatar);
    avatar.setImageUrl("http://someurl.com/image.png",mImageLoader);

Singleton Pattern

Google recommends that you use a common RequestQueue object for your app in the form of a Singleton. This is also something that is glossed over in examples, so have another one on us.

VolleySingleton.java

import android.content.Context;
package com.company.myapplication;

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

public class VolleySingleton {
    private static VolleySingleton mInstance = null;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;

    private VolleySingleton(){
        mRequestQueue = Volley.newRequestQueue(MyApplication.getAppContext());
        mImageLoader = new ImageLoader(this.mRequestQueue, new ImageLoader.ImageCache() {
            private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(10);
            public void putBitmap(String url, Bitmap bitmap) {
                mCache.put(url, bitmap);
            }
            public Bitmap getBitmap(String url) {
                return mCache.get(url);
            }
        });
    }

    public static VolleySingleton getInstance(){
        if(mInstance == null){
            mInstance = new VolleySingleton();
        }
        return mInstance;
    }

    public RequestQueue getRequestQueue(){
        return this.mRequestQueue;
    }

    public ImageLoader getImageLoader(){
        return this.mImageLoader;
    }

}

You’ll need to implement a static application context in a class which extends Application. Then, update line 15 of VolleySingleton.java to call your static context getter method. An example of what this application class might look like can be found here: MyApplication.java

Using the Singleton is as simple as:

RequestQueue queue = VolleySingleton.getInstance().getRequestQueue();

//or

mImageLoader = VolleySingleton.getInstance().getImageLoader();

Download

Get the singleton and instructions from our GitHub repo here https://github.com/CypressNorth/Volley-Singleton

The following two tabs change content below.

Matthew Mombrea

Matt is a longtime entrepreneur and software engineer. He is a founder of Cypress North, and chief technology officer. Matt also contributes to the community as a columnist on ITworld.com.

23 Comments

  • Kumar Saurav
    on October 11, 2013 Reply

    Dumping volley for Picasso and retrofit combo.

  • Delton Childs
    on November 3, 2013 Reply

    How is it that this article has no comments… this code is epic. It works perfectly. It’s so hard to find good documentation on Volley and the whole image loading with recycled views is a huge hurdle for beginners. I can’t thank you enough!

  • Shervin Asgari
    on November 6, 2013 Reply

    Thank you for this. This cleared up a few things for me.
    Now I will use Volley in my application.

  • Vivek Bhusal
    on November 13, 2013 Reply

    This is the perfect example I have found about ImageView Loader on the Internet till date.. Thanks for sharing

  • bertslike
    on November 28, 2013 Reply

    Thank you so much for this post, I finally managed to understand the whole concept!

  • Krste
    on November 28, 2013 Reply

    Great post, Thanks ;)

  • soma
    on January 6, 2014 Reply

    Thanks for this great Article, I would recomend you to store the RequestQueue in Application or MainActivity and acces it from there via a getter. THANK YOU VERY MUCH!

    • Matthew Mombrea
      on January 6, 2014 Reply

      You’re welcome. I think that the singleton pattern is the recommended way to handle the RequestQueue.

  • abi V.R
    on January 28, 2014 Reply

    http://stackoverflow.com/questions/16682595/android-volley-imageloader-bitmaplrucache-parameter

    check this one to make it perfect , and allow the size of cache

  • abi V.R
    on January 28, 2014 Reply

    Also how to set a place holder till the image is loaded and is there is any listener for checking whether the image is set to Image view . Consider a condition in which a progress indicator is shown until image is loded ti view.

  • Fabio
    on February 20, 2014 Reply

    Really brief and concise, but great !! You saved me from a good headache here.
    PS: It would be great if you post the files for non advanced users, it used to hep me a lot.

  • Vijay Dhama
    on February 26, 2014 Reply

    Thanks for the post. Singleton Pattern seems to make sense. Is it not common for networkimageview to face OutOfMemory errors?

    • Matthew Mombrea
      on February 26, 2014 Reply

      I haven’t experienced any out of memory issues to date but I can’t say I know for sure

  • Jean-François Cartier
    on March 2, 2014 Reply

    The problem I see using a Singleton here is that the constructor takes one argument (a Context object). An object requiring a parameter in the constructor cannot be a Singleton per se. Let’s say we have ActivityA and ActivityB. ActivityA calls VolleySingleton.getInstance(this). Later, ActivityB calls VolleySingleton.getInstance(this). It will return the instance created by ActivityA since mInstance != null. What if the context is not available anymore (i.e. ActivityA has been destroyed). Does it crash?

    • Matthew Mombrea
      on March 2, 2014 Reply

      Jean-Francois,

      Very good point. I’ll have to fire up the debugger to see exactly what’s going on in that scenario. I’m using this VolleySingleton in several Activities and haven’t experienced any issues yet. I suspect (but it’s just a guess at this point) that each time a new Activity is loaded the previous Activity is unloaded, along with the instance of the singleton. In that way, the singleton would be scoped to the life of that activity. I have no idea if that’s true or not but when I have a moment I’ll step through an example and figure it out. If it does indeed crash between Activities, I’ll be sure to update this post and the Github. Thank you!

      • Jean-François Cartier
        on March 2, 2014 Reply

        I don’t think that the singleton would be scoped to the lifecycle of an Activity. To resolve this I thought about creating the singleton in an Application object (https://developer.android.com/reference/android/app/Application.html). However, reading the documentation about this class lead me to the solution:
        “If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton.”

        From what I understand passing any Context would do, but I think that it would even be better if the constructor and getInstance would not require any Context and use Context.getApplicationContext() internally in the constructor. What do you think?

        • Matthew Mombrea
          on March 2, 2014 Reply

          I think you’re right, and that sounds like a good solution. Looking at the Volley newRequestQueue method (which requires the context), the comment for the context is “context A {@link Context} to use for creating the cache dir.”

          If it’s only being used to get/create the cache directory, the application context seems appropriate.

          • Jean-François Cartier
            on March 2, 2014

            Totally agree.

          • Matthew Mombrea
            on March 4, 2014

            The Github repo has been updated with your contribution, thanks! I tested out the situation and, while the different contexts didn’t crash the app, they also were generating different cache files, effectively limiting the loader cache to a single Activity rather than the whole application. This solution is much better.

  • Deep Shah
    on July 5, 2014 Reply

    It’s nice article .

    The best way to maintain volley core objects and request queue is, making them global by creating a singleton class which extends Application object and create your singleton implementation within this class .

  • Ashish
    on September 5, 2014 Reply

    The way volley works Its totally disaster.If You are working with high resolution image and you are downloading 500 hundred images,It never work.OutOfMemory error does not handled by volley.

    • Matthew Mombrea
      on September 5, 2014 Reply

      Ashish,

      That is not a problem with volley, it’s a problem with the strategy. All mobile applications have a limited amount of memory to work with which is governed by the OS. You need to be careful with the size and number of images that you’re loading into memory and displaying at once. No library will help you load 500 high-res images onto a mobile app at once.

Leave a Reply