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