Setting up the Android Google Volley ImageLoader for NetworkImageView

android
POST
mmombrea-headshot
By Matt Mombrea
Share

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

POST
mmombrea-headshot
By Matt Mombrea
Share

31 Comments

  1. Author's Headshot
    Kumar Saurav October 11, 2013
    Reply

    Dumping volley for Picasso and retrofit combo.

  2. Author's Headshot
    Delton Childs 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!

  3. Author's Headshot
    Shervin Asgari November 6, 2013
    Reply

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

  4. Author's Headshot
    Vivek Bhusal November 13, 2013
    Reply

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

  5. Author's Headshot
    bertslike November 28, 2013
    Reply

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

  6. Author's Headshot
    Krste November 28, 2013
    Reply

    Great post, Thanks 😉

  7. Author's Headshot
    soma 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!

    • Author's Headshot
      Matthew Mombrea January 6, 2014

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

  8. Author's Headshot
    abi V.R 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

  9. Author's Headshot
    abi V.R 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.

  10. Author's Headshot
    Fabio 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.

  11. Author's Headshot
    Vijay Dhama February 26, 2014
    Reply

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

    • Author's Headshot
      Matthew Mombrea February 26, 2014

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

  12. Author's Headshot
    Jean-François Cartier 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?

    • Author's Headshot
      Matthew Mombrea March 2, 2014

      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!

    • Author's Headshot
      Jean-François Cartier March 2, 2014

      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?

    • Author's Headshot
      Matthew Mombrea March 2, 2014

      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.

    • Author's Headshot
      Jean-François Cartier March 2, 2014

      Totally agree.

    • Author's Headshot
      Matthew Mombrea 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.

  13. Author's Headshot
    Deep Shah 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 .

  14. Author's Headshot
    Ashish 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.

    • Author's Headshot
      Matthew Mombrea September 5, 2014

      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.

  15. Author's Headshot
    Sam Harris October 9, 2014
    Reply

    Has anyone used the ImageLoader for Https requests. I need to put some basic authorization into my requests but don't see a simple way to do that with the ImageLoader

  16. Author's Headshot
    Vladimir Makarov January 29, 2015
    Reply

    hi, Matthew Mombrea, its a fantastic article but I have a few doubts, if the ImageCache works as intended , why are people discussing issues and shortcomings about the ImageCaching here http://stackoverflow.com/questions/21848749/volley-image-caching and infact going to the extent of using a custom DiskBasedCache made by Jake Wharton, the founder of sherlockactionbar, does the LruCache work inside an adapter such as a BaseAdapter's getView or RecyclerView.Adapter's onBindViewHolder , I have used other libraries in the past such as Picasso and UniversalImageLoader to manage images downloaded from a url inside a ListView or RecyclerView, however I feel Volley is missing something, can you please enlighten me on it, thanks in advance

    • Author's Headshot
      Matthew Mombrea January 29, 2015

      Vlad,

      The reason for the confusion is the lack of documentation on how the cache is supposed to be used with Volley. In that StackOverflow thread, the question shows the person using the LruCache within the OnCreate method of a fragment. It doesn't look as if he's creating a VolleySingleton using a single context for cache, or even the fragment for that matter. If you don't use a singleton and you don't use a common context, the cache won't work as you expect.

      Even using a singleton, you need to be careful about the context you give it. If you look back in this comment thread, Jean-François Cartier caught a mistake in my code related to the cache context. It's since been updated and works as you'd expect.

      Here's the link to the repo showing how to use the singleton pattern with volley + LruCache:
      https://github.com/CypressNorth/Volley-Singleton

  17. Author's Headshot
    umeshisran405 May 14, 2015
    Reply

    Nice post on volley.. The discussions help a lot..

  18. Author's Headshot
    haoc June 5, 2015
    Reply

    Nice post!
    Since this is a singleton pattern, I think it is necessary to make sure it is thread safe.:)

  19. Author's Headshot
    gordonpassy August 10, 2015
    Reply

    Very helpful

  20. Author's Headshot
    Bruno March 17, 2019
    Reply

    Thank you!

  21. Author's Headshot
    someone June 18, 2020
    Reply

    PERFECT!!! thank you so much

Leave a Reply

Your email address will not be published. Required fields are marked *

Meet the Author

mmombrea-headshot
CTO / Partner

Matthew Mombrea

Matt is our Chief Technology Officer and one of the founders of our agency. He started Cypress North in 2010 with Greg Finn, and now leads our Buffalo office. As the head of our development team, Matt oversees all of our technical strategy and software and systems design efforts.

With more than 19 years of software engineering experience, Matt has the knowledge and expertise to help our clients find solutions that will solve their problems and help them reach their goals. He is dedicated to doing things the right way and finding the right custom solution for each client, all while accounting for long-term maintainability and technical debt.

Matt is a Buffalo native and graduated from St. Bonaventure University, where he studied computer science.

When he’s not at work, Matt enjoys spending time with his kids and his dog. He also likes to golf, snowboard, and roast coffee.