How do I properly set up Volley to download images

2019-04-08 16:06发布

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);
}

}

5条回答
forever°为你锁心
2楼-- · 2019-04-08 16:41

(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.)
查看更多
姐就是有狂的资本
3楼-- · 2019-04-08 16:47

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) {

                }
            });
查看更多
该账号已被封号
4楼-- · 2019-04-08 16:47

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

查看更多
SAY GOODBYE
5楼-- · 2019-04-08 16:55

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);
查看更多
登录 后发表回答