Question

I am trying to understand Volley's image caching. I have a fragment with gridview inside it, which will load around 12-30 images. There images are retrieved from server and i am using NetworkImageView for loading these images.

I am able to display the images in the NetworkImageView and everything works fine. But, when I change from one fragment to another and come back to the previous fragment, in LogCat, I see that Volley is trying to fetch the images again.

I read Volley automatically takes care of Image Caching. When the image is cached in the first fragment, why is it trying to get the image again, when i came back from second to first? In the first place, is the LogCat data, showing Volley's image requests? or something else...

Below is my code:

In onCreate()

queue = Volley.newRequestQueue(getActivity());
imageLoader = new ImageLoader(queue, 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);
    }
});

Logcat when loaded the fragment for first time :

02-18 14:21:20.724: D/Volley(14713): [4944] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-11-57-29-pm.png 0x800c5bdc LOW 2> [lifetime=3782], [size=398563], [rc=200], [retryCount=0]
02-18 14:21:20.874: D/Volley(14713): [4943] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://xx.files.wordpress.com/2014/02/st-vincent.jpg 0x800c5bdc LOW 3> [lifetime=3941], [size=501475], [rc=200], [retryCount=0]
02-18 14:21:20.894: D/Volley(14713): [1] Request.finish: 4181 ms: [ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-11-57-29-pm.png 0x800c5bdc LOW 2
02-18 14:21:20.974: D/Volley(14713): [1] Request.finish: 4260 ms: [ ] http://xx.files.wordpress.com/2014/02/st-vincent.jpg 0x800c5bdc LOW 3
02-18 14:21:20.994: D/dalvikvm(14713): GC_FOR_ALLOC freed 1914K, 6% free 68371K/72184K, paused 11ms, total 11ms
02-18 14:21:20.994: I/dalvikvm-heap(14713): Grow heap (frag case) to 72.368MB for 5843106-byte allocation
02-18 14:21:21.014: D/dalvikvm(14713): GC_FOR_ALLOC freed 1K, 5% free 74076K/77892K, paused 15ms, total 15ms
02-18 14:21:21.074: D/Volley(14713): [1] Request.finish: 4336 ms: [ ] http://xx.files.wordpress.com/2014/02/underwater.gif 0x800c5bdc LOW 8
02-18 14:21:21.214: D/Volley(14713): [4945] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-4-24-04-pm.png 0x800c5bdc LOW 5> [lifetime=4155], [size=482380], [rc=200], [retryCount=0]
02-18 14:21:21.244: D/Volley(14713): [1] Request.finish: 4494 ms: [ ] http://xx.files.wordpress.com/2014/01/albarn-everyday-robots.jpg 0x800c5bdc LOW 9
02-18 14:21:21.274: D/Volley(14713): [1] Request.finish: 4551 ms: [ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-4-24-04-pm.png 0x800c5bdc LOW 5
02-18 14:21:21.994: D/Volley(14713): [1] Request.finish: 5244 ms: [ ] http://xx.files.wordpress.com/2014/02/macdemarco_baby.jpg 0x800c5bdc LOW 10
02-18 14:21:22.934: D/Volley(14713): [1] Request.finish: 6183 ms: [ ] http://xx.files.wordpress.com/2014/01/nenehcherry_lank01.jpg 0x800c5bdc LOW 11

When I come back to the same fragment the second time: Just visited second fragment and came back to first fragment - Not much a gap in between..

02-18 14:27:46.164: D/dalvikvm(14713): GC_FOR_ALLOC freed 29047K, 26% free 91776K/122752K, paused 23ms, total 23ms
02-18 14:27:47.994: D/dalvikvm(14713): GC_FOR_ALLOC freed 2957K, 21% free 97010K/122752K, paused 20ms, total 20ms
02-18 14:27:48.274: D/Volley(14713): [1] Request.finish: 3244 ms: [ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-2-58-16-pm.png 0x800c5bdc LOW 6
02-18 14:27:48.294: D/dalvikvm(14713): GC_FOR_ALLOC freed 2007K, 21% free 97932K/122752K, paused 14ms, total 14ms
02-18 14:27:48.324: D/Volley(14713): [4956] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-11-57-29-pm.png 0x800c5bdc LOW 2> [lifetime=3272], [size=398563], [rc=200], [retryCount=0]
02-18 14:27:48.484: D/Volley(14713): [1] Request.finish: 3456 ms: [ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-11-57-29-pm.png 0x800c5bdc LOW 2
02-18 14:27:48.974: D/dalvikvm(14713): GC_FOR_ALLOC freed 1030K, 15% free 104815K/122752K, paused 56ms, total 56ms
02-18 14:27:49.054: D/Volley(14713): [1] Request.finish: 4022 ms: [ ] http://xx.files.wordpress.com/2014/02/screen-shot-2014-02-17-at-4-24-04-pm.png 0x800c5bdc LOW 5
02-18 14:27:49.314: D/Volley(14713): [1] Request.finish: 4276 ms: [ ] http://xx.files.wordpress.com/2014/01/albarn-everyday-robots.jpg 0x800c5bdc LOW 9
02-18 14:27:49.374: D/Volley(14713): [1] Request.finish: 4325 ms: [ ] http://xx.files.wordpress.com/2014/01/nenehcherry_lank01.jpg 0x800c5bdc LOW 11
02-18 14:27:49.404: D/Volley(14713): [1] Request.finish: 4355 ms: [ ] http://xx.files.wordpress.com/2014/02/macdemarco_baby.jpg 0x800c5bdc LOW 10
02-18 14:27:49.654: D/dalvikvm(14713): GC_FOR_ALLOC freed 1456K, 12% free 108705K/122752K, paused 27ms, total 27ms
02-18 14:27:49.734: D/Volley(14713): [1] Request.finish: 4691 ms: [ ] http://xx.files.wordpress.com/2014/02/underwater.gif 0x800c5bdc LOW 8
02-18 14:27:50.304: D/dalvikvm(14713): GC_FOR_ALLOC freed 11584K, 16% free 103314K/122752K, paused 47ms, total 47ms
02-18 14:27:50.334: D/Volley(14713): [1] Request.finish: 5281 ms: [ ] http://xx.files.wordpress.com/2014/02/echo-and-the-bunnymen.jpg 0x800c5bdc LOW 12

As the links show, Volley is accessing the same URLs. Is Volley trying to get images from server? or is it just showing the urls that it is loading from cache?

How do I make Volley cache images? If it's not handling the caching right now, with my code above, what should i do to achieve it?

I have tried changing the maxSize value from 10 to 100*1024*1024 (100MB) but that didn't stop from Volley outputting the same values.

Était-ce utile?

La solution

Volley did not gave caching option directly. you have to make your own with in the tool provide by Volley. See Network Image caching, Jake Wharton had written about caching mechanism using Volley. Jake Wharton's Volley Customization

Autres conseils

You can see in the link below, the continuation of my question for implementing Image Caching with Volley using Jake Wharton's DiskLruCache and VolleyImageCacheExample. It's working as expected and images are getting cached. Thanks for all your help.

JakeWharton's DiskLruCache - How to Implement with Volley?

Are you using Volley as a singleton? If you're not, and you're not using a common context for the requestQueue, it won't work the way you expect. The documentation on this part of Volley is particularly unhelpful (at least since I used it last). Once configured properly it will read/write from the cache as you would expect.

Here is a GitHub project with a VolleySingleton class you can use along with examples: CypressNorth/Volley-Singleton

Here is a blog post describing the setup in more detail: Setting up the Android Google Volley ImageLoader for NetworkImageView

Consider using Glide which android recommends for loading images in your app. Compared to volley, Glide provides automatic image caching.

To add Glide in your app:

Step 1 ) Update build.gradle file

dependencies {
    compile 'com.github.bumptech.glide:glide:3.6.1'
    compile 'com.android.support:support-v4:19.1.0'
  }

Step 2) Add INTERNET permission in manifest file

<uses-permission android:name="android.permission.INTERNET" />

Step 3) Add ImageView in you layout

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/imageView"
    >
</ImageView>

Step 4) Glide Usage in Activity

    //Initialize ImageView
    ImageView imageView = (ImageView) findViewById(R.id.imageView);

    //Loading image from below url into imageView
   Glide.with(this)
        .load("IMAGE URL HERE")
        .placeholder(R.drawable.placeholder)
        .error(R.drawable.imagenotfound)
        .override(200, 200);
        .centerCrop();
        .into(imageView);

Read more on Android Glide Library

You can check this, I had enabled L1 and L2 caching mechanism for Volley.

Volley with Caching . Please make sure that cache control should be enabled in the response header.

The simplest way to cache images with Volley I found, was to use a RequestQueue with a DiskBasedCache. My goal was to reduce bandwidth, rather than loading times. This keeps the memory footprint low as well.

 val cacheSizeInMegabytes = 5
 val cacheSizeInBytes = cacheSizeInMegabytes * 1024 * 1024
 val cacheDir = File(context.cacheDir, "volleyCache")
 val cache = DiskBasedCache(cacheDir, cacheSizeInBytes)

 val httpStack = HurlStack()
 val networkStack = BasicNetwork(httpStack)

 val queue = RequestQueue(cache, networkStack)
 queue.start()

Then just use the queue and make sure to have request.setShouldCache(true) (or not).

A very rude way but it works :)

package it.dataware.passaeprendi.app.util;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.LruCache;

import com.android.volley.VolleyLog;
import com.android.volley.toolbox.ImageLoader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;

// https://stackoverflow.com/questions/14053338/save-bitmap-in-android-as-jpeg-in-external-storage-in-a-folder
// https://stackoverflow.com/questions/8710515/reading-an-image-file-into-bitmap-from-sdcard-why-am-i-getting-a-nullpointerexc

public class DiskBitmapCache implements ImageLoader.ImageCache {
private File   cacheDir;

// ...
private  static final String CACHE_PATH      = "dataware/passaeprendi/imagechache/";
private  static final String CACHE_FULL_PATH = Environment.getExternalStorageDirectory() + "/" + CACHE_PATH;
private  static final int    MAX_IMAGE_AGE   = 5; // in days

private  static final BitmapFactory.Options options = new BitmapFactory.Options();
static {
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
}

public DiskBitmapCache() {
    cacheDir = new File(CACHE_FULL_PATH);
    cacheDir.mkdirs();
}

private static  ImageLoader.ImageCache imageLoaderCache = new ImageLoader.ImageCache() {
    private final LruCache<String, Bitmap> mCache = new LruCache<>(30);

    public void putBitmap(String url, Bitmap bitmap) {
        mCache.put(url, bitmap);
    }
    public Bitmap getBitmap(String url) {
        return mCache.get(url);
    }
};

public Bitmap getBitmap(String url) {

    final String volleyFileName = getFilenameForKey(url);

    final Bitmap bitmapL1 = imageLoaderCache.getBitmap(volleyFileName);
    if (bitmapL1 != null) {
        // VolleyLog.d("taken from cache L1 :" + url + " -> " + volleyFileName + ".");
        return bitmapL1;
    }

    final File volleyCacheFile = new File(cacheDir, volleyFileName);

    if (!volleyCacheFile.exists()) {
        return null;
    }

    // =======================================
    // age check
    // =======================================

    long diff = new Date().getTime() - volleyCacheFile.lastModified();

    if (diff > MAX_IMAGE_AGE * 24 * 60 * 60 * 1000) {
        volleyCacheFile.delete();
        return null;
    }

    // =======================================
    // load from disk
    // =======================================

    Bitmap bitmap = BitmapFactory.decodeFile(volleyCacheFile.getAbsolutePath(), options);

    if (bitmap != null) {
        //     VolleyLog.d("taken from cache L2 :" + url + " -> " + volleyFileName + ".");
        imageLoaderCache.putBitmap(volleyFileName, bitmap);
    }

    // VolleyLog.d("taken from cache L2 :" + url + " -> " + volleyFileName + ".");
    return bitmap;
}

public void putBitmap(String url, Bitmap bitmap) {
    final String volleyFileName = getFilenameForKey(url);

    File volleyCacheFile = new File(cacheDir, volleyFileName);

    try {
        // ...
        FileOutputStream fos = null;
        volleyCacheFile.createNewFile();
        fos = new FileOutputStream(volleyCacheFile, false);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
        fos.flush();
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// Volley creates a filename for the url with the following function, so we'll use the same function
// for translating the url back to said filename
private String getFilenameForKey(String key) {
    int firstHalfLength = key.length() / 2;

    // ..
    String  localFilename   = String.valueOf(key.substring(0, firstHalfLength)  .hashCode());
            localFilename  += String.valueOf(key.substring(firstHalfLength)     .hashCode());
            localFilename  += ".jpg";

    return localFilename;
}
}    

I hope will help someone.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top