Volley Image Caching
Asked Answered
M

7

15

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.

Melanimelania answered 18/2, 2014 at 9:6 Comment(0)
C
11

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

Contributory answered 18/2, 2014 at 9:14 Comment(6)
Ok.. Will look into it. While going through other questions, I found this link, #16683095 Can I use this way to cache my images?Melanimelania
May be.. But this caching explain memory caching for disk-cache you had to use Jake solutionContributory
Okie.. Thanks for your help. Will check the Jake's solution and get back to you. Upvoted.Melanimelania
Be careful not to use a disk based cache, like the one Jake Wharton wrote, where Volley expects a memory cache.Numbing
@ItaiHanski May be it cause harm in some cases but in most cases it not feasible to download all image again once application start. Importantly when you have lot of ImagesContributory
@Sameer If you supply a disk cache instead of a memory cache where a memory cache is expected, you will be using 2 disk caches because Volley already has a disk cache. This is bad because not only will the performance be bad, but you will take up twice as much disk space which will contain mostly duplications.Numbing
M
1

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?

Melanimelania answered 19/2, 2014 at 9:16 Comment(0)
G
1

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

Gaiter answered 29/1, 2015 at 15:18 Comment(0)
G
1

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

Gallinacean answered 14/6, 2016 at 5:44 Comment(0)
U
0

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.

Urata answered 2/4, 2015 at 14:23 Comment(0)
P
0

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

Prothesis answered 4/12, 2018 at 12:8 Comment(0)
C
0

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://mcmap.net/q/544456/-save-bitmap-in-android-as-jpeg-in-external-storage-in-a-folder
// https://mcmap.net/q/194749/-reading-an-image-file-into-bitmap-from-sdcard-why-am-i-getting-a-nullpointerexception

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.

Cabanatuan answered 7/7, 2020 at 18:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.