12

Hi I am trying to use the HttpResponseCache introduced in Android 4.The docs do talk clearly about how to install the cache but I am at a complete loss on how to cache Images downloaded from the net.Earlier I was using the DiskLruCache to cache them. Would anyone point me towards some examples of working code where HttpResponseCache has been used..

Edit:- Can someone tell me what I am doing wrong here:-

MainActivity.java
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    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);
        Log.v(TAG,"cache set up");
    } catch (Exception httpResponseCacheNotAvailable) {
        Log.v(TAG, "android.net.http.HttpResponseCache not available, probably because we're running on a pre-ICS version of Android. Using com.integralblue.httpresponsecache.HttpHttpResponseCache.");
        try{
            com.integralblue.httpresponsecache.HttpResponseCache.install(httpCacheDir, httpCacheSize);
        }catch(Exception e){
            Log.v(TAG, "Failed to set up com.integralblue.httpresponsecache.HttpResponseCache");
        }
    }
    TheMainListFrag gf=(TheMainListFrag) getSupportFragmentManager().findFragmentByTag("thelistfrags");
    if(gf==null){
        gf=TheMainListFrag.newInstance();
        FragmentTransaction ft=getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.thelefty, gf,"thelistfrags");
        ft.commit();
    }
}

Then in the loader of TheMainListFrag, I do the below:-

public ArrayList<HashMap<String,String>> loadInBackground() {
    String datafromServer = null;
    ArrayList<HashMap<String,String>> al = new ArrayList<HashMap<String,String>>();
    try {
        String url = "someurl";
        HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();

        urlConnection.setRequestProperty("Accept", "application/json");
        InputStream is = new BufferedInputStream(urlConnection.getInputStream());
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        datafromServer=sb.toString();
        Log.v("fromthread",datafromServer);
        // etc 
                    //etc

    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (Exception e) {
        Log.v("fromthread", e.getClass() + "--" + e.getMessage());
    }

    return al;
}

When i am connected to internet, it works fine, and in the directory http-the cache directory named above, i can see the files too. But when I am not connected to the internet, the data refuses to load.

When i load images from the net, i see the cache files named as .tmp , which i believe are termed as dirty as per DiskLruCache.

Please let me know if there is any other info that you want me to provide

Jonik
  • 80,077
  • 70
  • 264
  • 372
Rasmus
  • 8,248
  • 12
  • 48
  • 72
  • HttpResponseCache only works with Http(s)URLConnection. Are you using these calls? Here's an example: http://developer.android.com/reference/android/net/http/HttpResponseCache.html – Harald Wilhelm Jul 20 '12 at 18:22
  • Yup all done exactly like that.. I am even using candrews library for backporting ..I see that json responses are getting cached but am unable to cache Bitmaps... – Rasmus Jul 20 '12 at 18:25
  • Why are you using reflection? – IgorGanapolsky Feb 13 '18 at 15:15

3 Answers3

11

From the section Force a Cache Response on the HttpResponseCache documentation:

Sometimes you'll want to show resources if they are available immediately, but not otherwise. This can be used so your application can show something while waiting for the latest data to be downloaded. To restrict a request to locally-cached resources, add the only-if-cached directive:

try {
    connection.addRequestProperty("Cache-Control", "only-if-cached");
    InputStream cached = connection.getInputStream();
    // the resource was cached! show it
} catch (FileNotFoundException e) {
    // the resource was not cached
}

This technique works even better in situations where a stale response is better than no response. To permit stale cached responses, use the max-stale directive with the maximum staleness in seconds:

int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
connection.addRequestProperty("Cache-Control", "max-stale=" + maxStale);
Radiodef
  • 37,180
  • 14
  • 90
  • 125
Jesse Wilson
  • 39,078
  • 8
  • 121
  • 128
  • Thanks Jesse.. That did the job... However when I download images from the net they are shown with .tmp extension. This does not seem to happen when I use the DiskLruCache directly. – Rasmus Jul 30 '12 at 08:26
  • will using the HttpResponseCache use heap memory or native memory? – android developer Oct 21 '13 at 10:18
  • +1. In my case, just setting `max-stale` in the requests fixed the situation that nothing was actually read from HttpResponseCache. – Jonik Oct 31 '13 at 16:31
  • 1
    Hmm, actually `connection.setUseCaches(true);` was sufficient for me. – Jonik Oct 31 '13 at 16:53
1

When you enable HttpResponseCache, all HttpUrlConnection queries will be cached. You can't use it to cache arbitrary data, so I'd recommend keep using DiskLruCache for that.

Marcus Forsell Stahre
  • 3,766
  • 1
  • 17
  • 14
  • HttpResponseCache does not work with HttpClient.It works with HttpUrlConnection. Yes It automatically caches all my json etc.. But Does the HttpResponseCache implementation not use the DiskLruCache internally. If so cant it be used to cache Bitmaps too – Rasmus Jul 20 '12 at 18:24
  • 1
    Yes, I'm sorry - I shouldn't have typed it just from memory. What I meant is that actual `Bitmap` objects aren't stored in the cache. However, HTTP requests for images should be cached, if that's what you mean. Corrected my answer. – Marcus Forsell Stahre Jul 20 '12 at 18:44
  • Could you please elaborate a little more on -->"When you enable HttpResponseCache, all HttpUrlConnection queries will be cached".. – Rasmus Jul 20 '12 at 18:49
  • 1
    If you install the HttpResponseCache, it will cache all responses that you get using HttpUrlConnection. That means that when you make the same request again, you can get a cached response immediately, without even sending anything over the network. – Marcus Forsell Stahre Jul 20 '12 at 18:56
  • The images I am talking of are the ones which are obtained from the HttpUrlConnection, I mean they are being downloaded from the net. It is not arbitrary data – Rasmus Jul 21 '12 at 06:55
  • With arbitrary data I meant arbitrary objects (you can't use HttpResponseCache as a general cache where you put in anything) - any data you receive using HttpUrlConnection will however be cached. So yes, your images will be cached. – Marcus Forsell Stahre Jul 21 '12 at 11:57
1

In my case HttpResponseCache wasn't actually caching anything. What fixed it was simply:

connection.setUseCaches(true);

(This must be called on the HttpURLConnection before establishing connection.)

For finer grained control, max-stale can be used as Jesse Wilson pointed out.

Community
  • 1
  • 1
Jonik
  • 80,077
  • 70
  • 264
  • 372