How do I properly set up Volley to download images from a URL
Asked Answered
L

5

5

I know Volley is supposed to make downloading and caching images mindlessly simple but yet I have been struggling for hours to properly implement it. I've looked around the net as well as the many articles on stackoverflow regarding volley but none of the examples I've found seem to work for me.

I only want to use volley to download and cache images from a given url, not to do any HTTP JSON REST handling. Just to take given urls, download the bitmaps and set them to the imageview then add them to the cache.

This has been my latest attempt so far. How do I load and cache images with volley correctly?

if (data.getImageUrl() != null) {
        try {

            holder.thumbnail.setTag(data.getImageUrl());

        Cache cache = ImgController.getInstance().getRequestQueue().getCache();
        Cache.Entry entry = cache.get(data.getImageUrl());

            if (entry != null) {
                try {
                    String cImg = new String(entry.data, "UTF-8");
                    LruBitmapCache bitmapCache = new LruBitmapCache();
                    holder.thumbnail.setImageBitmap(bitmapCache.getBitmap(cImg));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

            } else {

                ImageLoader imageLoader = ImgController.getInstance().getImageLoader();

                imageLoader.get(data.getImageUrl(), new ImageListener() {

                    @Override
                    public void onErrorResponse(VolleyError error) {

                        holder.thumbnail.setImageResource(R.drawable.filler_icon);

                    }

                    @Override
                    public void onResponse(ImageLoader.ImageContainer response, boolean arg1) {
                        if (response.getBitmap() != null) {
                            // load image into imageview
                            holder.thumbnail.setImageBitmap(response.getBitmap());

                        }
                    }
                });
            }

            return convertView;
        } catch (Exception e) {
            e.printStackTrace();
            Log.v(DEBUG_TAG, "no image: ", e);
            holder.thumbnail.setImageResource(R.drawable.filler_icon);


        }
    }else {
        return null;
    }


    return convertView;
}

When I run this I get a NullPointerException pointing to this line

Cache cache = ImgController.getInstance().getRequestQueue().getCache();

I've setup the following singleton class to handle requests

public class ImgController extends Application {

public static final String TAG = ImgController.class.getSimpleName();
private RequestQueue requestQueue;
private ImageLoader imageLoader;

private static ImgController instance;

@Override
public void onCreate() {
    super.onCreate();
    instance = this;

}
public static synchronized ImgController getInstance(){
    return instance;
}
public RequestQueue getRequestQueue(){
    if(requestQueue == null){
        requestQueue = Volley.newRequestQueue(getApplicationContext());
    }
    return this.requestQueue;
}
public ImageLoader getImageLoader(){
    getRequestQueue();
    if(imageLoader ==  null){
        imageLoader = new ImageLoader(this.requestQueue, new LruBitmapCache());
        }

    return this.imageLoader;
}
public <T> void addToRequestQueue(Request<T> req, String tag) {
    // set the default tag if tag is empty
    req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
    getRequestQueue().add(req);
}

public <T> void addToRequestQueue(Request<T> req) {
    req.setTag(TAG);
    getRequestQueue().add(req);
}

public void cancelPendingRequests(Object tag) {
    if (requestQueue != null) {
        requestQueue.cancelAll(tag);
    }
}

}

as well as the following LruBitmapCache class

public class LruBitmapCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache {

public static int getDefaultLruCacheSize(){
    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    final int cacheSize = maxMemory / 8;

    return cacheSize;
}

public LruBitmapCache() {
    this(getDefaultLruCacheSize());
}
public LruBitmapCache(int maxSize) {
    super(maxSize);
}

@Override
public Bitmap getBitmap(String url) {
    return get(url);
}

@Override
public void putBitmap(String url, Bitmap bitmap) {
    put (url, bitmap);
}

}

Lynda answered 28/7, 2014 at 3:47 Comment(1)
Check whether it generates any folder for cache images in your SD Card. If yes, then check does it having images or blank/empty? If it is blank , it means its not fetching images from given url else you need to check retrieving code of cache images from SDCard folder.Edmiston
V
11

(Sorry for poor english skill ^^;)

Volley is supposed to make downloading and caching images mindlessly simple

YEAH! Volley is VERY SIMPLE. you don't need to think about cache hit, image loading etc...

just use NetworkImageView. Belows are example.

layout_example.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <com.android.volley.toolbox.NetworkImageView
            android:id="@+id/photo"
            android:adjustViewBounds="true"
            android:scaleType="fitCenter"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

</RelativeLayout>

MainActivity.java

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.layout_example);
    NetworkImageView nv = (NetworkImageView) findViewById(R.id.photo);
    nv.setDefaultImageResId(R.drawable.default_image); // image for loading...
    nv.setImageUrl(imageUrl, ImgController.getInstance().getImageLoader()); //ImgController from your code.
}

NetworkImageView automatically loads image from background queue and cancel request when this view is detached using ImageLoader. and ImageLoader automatically uses memory lru cache and disk cache. NetworkImageView is best solution for you.

Additional Information

NetworkImageView
       |
  ImageLoader (uses `LruBitmapCache` you implemented.)
       |
 RequestQueue (uses `DiskBasedCache`. it is already implemented in volley.)
Various answered 28/7, 2014 at 4:30 Comment(6)
The problem is when I try to get an imageLoader Object it always returns null for some reason.Lynda
did you register your Custom Application context in AndroidManifest.xml file?Various
like this.<application android:name="ImgController" android:allowBackup="true" android:icon="@drawable/icon" android:label="@string/app_name">Various
adding that to my manifest causes gradle to throw the following error INSTALL_PARSE_FAILED_MANIFEST_MALFORMED I added the android:name="ImgController" because I had everything elseLynda
if you don't register your custom application(ImgController), imgController's onCreate() method will not be called and getInstance() will always return null. check your manifest file syntax. please upload your manifest file.Various
Hey, you were right! I had to refactor the ImgController to a different package to get it to work in the manifest is all. Thanks Cinakyn, I really appreciate your patience.Lynda
Y
10

A callback for Image Request is available for Volley, you can use the Following code below.

    ImageView iv = null; /*Attach the Pointer for ImageView*/
    RequestQueue requestAdministrator = null; /*Attach the Pointer for Volley*/

    ImageRequest ir = new ImageRequest(url, new Response.Listener<Bitmap>() {
        @Override
        public void onResponse(Bitmap response) {
            // callback
            iv.setImageBitmap(response);
        }
    }, 100, 100, null, null);
    // 100 is your custom Size before Downloading the Image.
    requestAdministrator.add(ir);
Yuki answered 16/1, 2015 at 5:46 Comment(0)
R
1

I have a more simple solution for displaying the image from url and storing it in cache. Without adding additional classes, only MainActivity. probably it will help somebody...

Here is my XML that displays only ImageView

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.natalie.volley.MainActivity">


    <ImageView
        android:id="@+id/ivImageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="50dp"/>

</android.support.constraint.ConstraintLayout>

And here is my MainAvtivity.java:

  import android.graphics.Bitmap;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.ImageView;

    import com.android.volley.RequestQueue;
    import com.android.volley.Response;
    import com.android.volley.VolleyError;
    import com.android.volley.toolbox.ImageRequest;
    import com.android.volley.toolbox.Volley;

    public class MainActivity extends AppCompatActivity {

        private String url = "http://kingofwallpapers.com/picture/picture-010.jpg";
        ImageView ivImageView;
        RequestQueue mRequestQueue;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ivImageView = (ImageView)findViewById(R.id.ivImageView);
            mRequestQueue = Volley.newRequestQueue(this.getApplicationContext());
            ImageRequest imageRequest = new ImageRequest(url, new BitmapListener(), 0, 0, null, null, new MyErrorListener());

            mRequestQueue.add(imageRequest);
        }

        private class BitmapListener implements Response.Listener<Bitmap> {
            @Override
            public void onResponse(Bitmap response) {
// response = your url's bitmap
                ivImageView.setImageBitmap(response);

            }
        }

        private class MyErrorListener implements Response.ErrorListener {
            @Override
            public void onErrorResponse(VolleyError error) {
//store a default image if connection failed
                ivImageView.setImageResource(R.drawable.error_icon);
            }
        }
    }

Don't forget to add <uses-permission android:name="android.permission.INTERNET" /> in Manifest.xml and compile 'com.android.volley:volley:1.0.0' in build.gradle dependencies

Rebarebah answered 30/3, 2017 at 17:29 Comment(0)
A
0

This is covered in the documentation: https://developer.android.com/training/volley/request.html#request-image

Afore answered 12/5, 2015 at 12:49 Comment(1)
It has been removed.Tnt
P
0

ImageRequest is deprecated so I am doing it as follows:

Step 1: Make Application class as below first

public class YourApplicationClass extends Application {
    private static YourApplicationClass sInstance;
    private RequestQueue mRequestQueue;
    private ImageLoader mImageLoader;

    public static YourApplicationClass getInstance(){
        return sInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;

        mRequestQueue = Volley.newRequestQueue(this);
        mImageLoader = new ImageLoader(this.mRequestQueue, new ImageLoader.ImageCache() {

            private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(10);

            public Bitmap getBitmap(String url) {
                return mCache.get(url);
            }

            @Override
            public void putBitmap(String url, Bitmap bitmap) {
                mCache.put(url, bitmap);
            }

        });
    }

    public RequestQueue getRequestQueue(){
        return mRequestQueue;
    }

    public ImageLoader getImageLoader(){
        return mImageLoader;
    }
}

Step 2: Now make a image request as follows from any activity or fragment

YourApplicationClass.getInstance().getImageLoader().get(image_url, new ImageLoader.ImageListener() {
                @Override
                public void onResponse(ImageLoader.ImageContainer imageContainer, boolean b) {
                 Bitmap bitmap = imageContainer.getBitmap();
                 //use bitmap 
                }

                @Override
                public void onErrorResponse(VolleyError volleyError) {

                }
            });
Pedicel answered 19/3, 2016 at 16:56 Comment(1)
I think the ImageRequest is not deprecated but the constructor that you are using is deprecated. use github.com/mcxiaoke/android-volley/blob/… instead of github.com/mcxiaoke/android-volley/blob/…Chenee

© 2022 - 2024 — McMap. All rights reserved.