HTTP Response Caching for Java and Android

HTTP caching is both important, as it reduces bandwidth use and improves performance, and complex, as the rules are far from simple. In my experience, most Java and Android applications either don’t do HTTP caching, or they roll their own and up doing it wrong or in way too complicated a fashion. In other words, they create a non-standard, one off, unmaintainable solution. And IMHO, that’s no solution at all.

If you find yourself using HttpClient, you can use HttpClient-Cache, which is an easy drop in for Java. See my previous post about HttpClient-Cache for Android. But if you’re using HttpUrlConnection (aka java.net.URL.openConnection()), there’s no good solution for regular Java or Android. Well, in Android 4.0 and later, you can use HttpResponseCache, but with only a small percentage of Android devices using 4.0 or later, that’s not a terribly good solution. If you use Android 4.0+’s HttpResponseCache as recommended by Google, then all previous Android versions end up with no HTTP response caching – this causes excess load on your servers, slower performance for the app, and unnecessary bandwidth use.

To fix this problem, I grabbed all the code from AOSP that implements Android 4.0’s HttpResponseCache and made it a separate library. This library is easy to use, works on Java 1.5+, all versions of Android, and is licensed under APLv2 (just like everything else in AOSP). Really, there’s no reason not to use it! You can even use in Java server applications, such as those that use Spring.

To use it, if you’re using Maven, simply add this block to your pom.xml (all artifacts are in Maven Central):
<dependency>
<groupId>
<com.integralblue</groupId>
<artifactId>httpresponsecache</artifactId>
<version>1.0.0</version>
</dependency>

If you’re not using Maven, you’ll need to add the httpresponsecache jar and its dependency, disklrucache.jar, to your project.

When your application starts, before it makes any HTTP requests, execute this method:
com.integralblue.httpresponsecache.HttpResponseCache.install(File directory, long maxSize);
If you’re using Android, and you want to use Android 4.0’s HttpResponseCache if it’s available, and fallback to this library if it’s not available:
final long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
final File httpCacheDir = new File(getCacheDir(), "http");
try {
Class.forName("android.net.http.HttpResponseCache")
.getMethod("install", File.class, long.class)
.invoke(null, httpCacheDir, httpCacheSize);
} catch (Exception httpResponseCacheNotAvailable) {
Ln.d(httpResponseCacheNotAvailable, "android.net.http.HttpResponseCache not available, probably because we're running on a pre-ICS version   of Android. Using c$
try{
com.integralblue.httpresponsecache.HttpResponseCache.install(httpCacheDir, httpCacheSize);
}catch(Exception e){
Ln.e(e, "Failed to set up com.integralblue.httpresponsecache.HttpResponseCache");
}
}

The source code to the library is available on GitHub. I’m already using it in my CallerID Android app. If you end up using this library, please leave me a comment.

That’s it – enjoy easy to use HTTP caching!

CC BY-SA 4.0 HTTP Response Caching for Java and Android by Craig Andrews is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

15 thoughts on “HTTP Response Caching for Java and Android

  1. I attempted to use HttpUrlConnection and your caching framework on top of that.
    Unfortunately, since HttpUrlConnection doesn’t work well on Android 2.3, I am forced to depend on HttpClient instead.
    HttpClient-Cache may be an easy drop-in on desktop implementations of Java – it is not an easy drop-in on Android. It depends on classes in the latest version of HttpClient that are not in the builtin Android classes and it is difficult to override them.

  2. @Chuck Doucette
    The HttpResponseCache library replaces the Android provided HttpUrlConnection implementation with the HttpUrlConnection implementation from Android 4.0. So if you’re concerned about problems that are in Android 2.3 that have been fixed in Android 4.0, then by using HttpResponseCache, you won’t have to worry about any of those possible Android 2.3 issues.

    I highly recommend that you do not use HttpClient (or HttpClient-Cache) as Android will not be maintaining its HttpClient library. Android HttpClient library has bugs that will not be fixed, and its not compatible with HttpClient-Cache as you noticed.

  3. Hi Craig. I tried out the code you’ve developed in Android 3.0 platform. It can be installed but when getting data from a site I built for testing, it seems it doesn’t cache the data at all. However, it does work on Android 4.x using the same site. Any suggestion?

  4. The thing is. There’s no error. It runs fine. I would test it by opening a web page that I serv with (max-age 60). Then I off the server and retry to connect. It is working on ICS but not on 3.x. Maybe you have any pointers on how to enable the stack trace?

  5. Hello Craig,

    I’m trying the library as a drop in replacement, I can see it is writing files to the cache I’ve set up, but I’m looking for a perf statistics and behavior to see if its working as I expect. First, is there a sample that has consistent behavior to ensure I’m using it properly?

    Secondly, despite seeing the written out cached files, the statistics reported are always zeros for network/hits/requests. I’ve tried looking at both:

    com.integralblue.httpresponsecache.HttpResponseCache.getInstalled();
    and
    com.integralblue.httpresponsecache.HttpResponseCache.getDefault();

    Both of which are non-null.

    Thoughts?

    Thanks,
    Kenny

    1. Which version are you using? The was a bug in 1.0 that prevented stats from working right (they were always 0 as you described). If you upgrade to 1.2, that problem will be resolved.

      I don’t have an example project that only shows this library being used. However, if you install using com.integralblue.httpresponsecache.HttpResponseCache.install(httpCacheDir, httpCacheSize); and then look at the stats, you should see it being used. If you find a bug, please let me know! Known issues can be found and new issues reported at https://github.com/candrews/httpresponsecache

  6. I started with the binaries, but now I’m building from the latest source from GitHub, I’ve added an optional logging interface to try to figure out what is and isn’t getting cached. I’ll let you know what I find. Thx.

  7. I am using the this library on android 4.0 but I am getting the IllegalAccessError while creating the HttpUrlConnection object. I tried using the following code

    final long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
    final File httpCacheDir = new File(getCacheDir(), “http”);
    try {
    Class.forName(“android.net.http.HttpResponseCache”)
    .getMethod(“install”, File.class, long.class)
    .invoke(null, httpCacheDir, httpCacheSize);
    } catch (Exception httpResponseCacheNotAvailable) {
    Ln.d(httpResponseCacheNotAvailable, “android.net.http.HttpResponseCache not available, probably because we’re running on a pre-ICS version of Android. Using c$
    try{
    com.integralblue.httpresponsecache.HttpResponseCache.install(httpCacheDir, httpCacheSize);
    }catch(Exception e){
    Ln.e(e, “Failed to set up com.integralblue.httpresponsecache.HttpResponseCache”);
    }
    }

    But in ICS I am getting the HttpResponseCache.getInstalled() returning null. If i use this library on pre ICS version its working fine. Please provide any suggestion to make it work on ICS as well.

  8. You say “The HttpResponseCache library replaces the Android provided HttpUrlConnection implementation with the HttpUrlConnection implementation from Android 4.0.” but it’s unclear how to use HttpResponseCache’s version of HttpUrlConnection. I found HttpURLConnectionImpl, but it is not visible to external packages.

  9. Ah, ok.

    It wasn’t clear if using the built in version would take advantage of the cache and the fixes to issues in older versions.

    Thanks for the help and the great library.

Leave a Reply to Chuck Doucette Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.