Enabling cache in sending http requests(Android, JAVA) - android

Just like a normal web browser, e.g, chrome,firefox, where cache is enabled, I want to send a http get request from my android activity using HTTPGET which will handle caching. How to do it?

I would suggest you to use Volley Library for all Networking Calls to make it more easier, efficient and fast.
Use it for caching the Requests and Memory Management.
Loading request from cache
Like below you can check for a cached response of an URL before making a network call.
Cache cache = AppController.getInstance().getRequestQueue().getCache();
Entry entry = cache.get(url);
if(entry != null){
try {
String data = new String(entry.data, "UTF-8");
// handle data, like converting it to xml, json, bitmap etc..
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
else{
// Cached response doesn't exists. Make network call here
}
Hope this helps !!

Related

Volley Cache returns null when receiving 304

I am trying to get Volley to work using its Cache. When I receive a 304 getCacheEntry().data is null even though "cache-control" is set. Here is what I am doing:
Volley gets instantiated likes this
// Instantiate the cache
Cache cache = new DiskBasedCache(c.getCacheDir(), 10 * 1024 * 1024); // 10 MB cap
// Set up the network to use HttpURLConnection as the HTTP client.
Network network = new BasicNetwork(new HurlStack());
// Instantiate the RequestQueue with the cache and network.
mRequestQueue = new RequestQueue(cache, network);
// Start the queue
mRequestQueue.start();
After sending a GET request I get the response 200 with "cache-control" set to "max-age=180, public". So far so good right?
If a GET request gets made twice or more I set "If-Modified-Since" with the last timestamp the request was made to the request header.
The second time I request a specific API endpoint the sever will respond with a 304. getCacheEntry().data returns null though. If I check the cache entries in Volleys RequestQueue I cannot find an entry for my specific request.
What am I doing wrong? For some reason I have one request that is always cached when fired once. It's even one that returns a lot of data. But all other requests aren't cached. Following code snippet parses the response and checks for 304.
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response, String charset) {
try {
String json = "";
if (!response.notModified) {
json = new String(response.data, charset);
} else {
//if not modified -> strangely getCacheEntry().data always null
json = new String(getCacheEntry().data, charset);
}
return Response.success(
gson.fromJson(json, clazz),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
I really appreciate any comments on this.
IMHO, your cache entry is always null (not only when getting 304 resp code), because of the following:
Cache cache = new DiskBasedCache(c.getCacheDir(), 10 * 1024 * 1024); // 10 MB cap
Please check your c.getCacheDir() to see if you want to use External Storage to store cache data, then you should set WRITE_EXTERNAL_STORAGE permission inside AndroidManifest.xml file.
Hope this helps!

Requesting JSON data and inserting into fragment

I have 3 tabs in my app, each having its own Fragment. I need to populate each tab's Fragment with data that needs to be retrieved from my website's REST API.
To my understanding, the onCreate/onCreateView method in the Fragment class is where I should request the JSON data (how do I request it?).
Then I would loop through the data and insert it into separate lists or cards (how do I do this?).
Sorry for the beginner questions, but I'm not sure where to begin.
There are two ways to do this
1) through native android
private void makeGetRequest() {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("http://www.example.com");
// replace with your url
HttpResponse response;
try {
response = client.execute(request);
Log.d("Response of GET request", response.toString());
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
2) use third party libraries.Please refer this url https://github.com/square/retrofit
Example
https://github.com/square/retrofit/blob/master/samples/src/main/java/com/example/retrofit/SimpleService.java
This library will do all the things like GET,POST,Sync,Async and Error Handling.
you have to use AsyncTask When youre requesting anything from server, Asynctask runs in backgrouns so your UI thread will no be blocked by it.
Otherwise you can try using Volly library dosen't need an AsyncTask to work. It will work in background thread anyway '
It also provides you with sucess failure handlers(if youre into ajax and all it'll easier for you)
take a look at Volly Library

volley - json caching is not working properly

Server sends me json object, expiration and ETAg.. I want to Voley save this object in cache and in next request for this object use request to the server including ETag in the header. If response will be 304 Not Modified, then it should use cached resource and if it will be 200 OK, it should use new resource from the server.
Volley doesn't send request at all (if the cache isn't expired) or if it is expired it sends new request with If-None-Match + etag string.. and server always response with 200
Volley will not issue a request to server at all if it detects that cache entry has not expired yet. Here are some code excerpts to prove it:
// If it is completely expired, just send it to the network.
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
And:
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response);
} else {
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
mDelivery.postResponse(request, response, new Runnable() {
#Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
You might want to control resource expiration on your server by setting max-age at Cache-Control or Expires headers in order to tweak cache on client side.

FileNotFoundException when using the offline cache of HttpResponsecache

I'm using HttpResponseCache to enable the response caching (for web requests) in my android app, and the offline cache isn't working.
I'm doing the offline cache as the documentation tells me to do.
In my Application class, at the onCreate method, I'm turning on the the cache with:
try {
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
File httpCacheDir = new File(getCacheDir(), "http");
Class.forName("android.net.http.HttpResponseCache")
.getMethod("install", File.class, long.class)
.invoke(null, httpCacheDir, httpCacheSize);
} catch (Exception httpResponseCacheNotAvailable) {}
At my HttpConnection class I'm getting the JSON with the method:
private String sendHttpGet(boolean cacheOnly) throws Exception {
URL url = new URL(getUrlCompleta());
HttpURLConnection urlConnection = null;
String retorno = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
if(urlConnection == null)
throw new Exception("Conn obj is null");
fillHeaders(urlConnection, cacheOnly);
InputStream in = new BufferedInputStream(urlConnection.getInputStream(), 8192);
retorno = convertStream(in);
in.close();
urlConnection.disconnect();
if(retorno != null)
return retorno;
} catch(IOException e) {
throw e;
} finally {
if(urlConnection != null)
urlConnection.disconnect();
}
throw new Exception();
}
Where the convertStream method just parse a InputStream into a String.
The method fillHeaders put an token on the request (for security reasons) and if the parameter cacheOnly is true, then the header "Cache-Control", "only-if-cached" is added to the request header ( with the code: connection.addRequestProperty("Cache-Control", "only-if-cached");)
The cache works 'fine' (with minor strange behaviors) when there is connectivity and the app hit the web server just to see if there is a newer version of the JSON. When the web server answers "nothing changed", the cache works.
The problem is when I have no connectivity and use the header "Cache-Control", "only-if-cached". In this case, I receive a java.io.FileNotFoundException: https://api.example.com/movies.json. That is awkward, because the implementation code of the cache probably stores the response in a file named using a hash function on the request url, and not the url itself.
Does anyone knows what can I do or what is wrong with my implementation?
ps: Above, I said "probably using a hash function", because I was not able to found the implementation of the com.android.okhttp.HttpResponseCache object (the class that android.net.http.HttpResponseCache delegates cache calls). If someone found it, please tell me where to look at :)
ps2: Even when I add a max-stale parameter in the Cache-Control header, it still doesn't work.
ps3: I obviously tested it on api 14+.
ps4: Although I'm accessing an "https://" URL address, the same behavior occurs when the URL is just a normal "http://" address.
It turns out that the problem was with the max-age value of the Cache-control directive in the response given by my web server. It had the following value: Cache-Control: max-age=0, private, must-revalidate. With this directive, my server was saying to the cache that the response could be used from the cache even if it was 0 seconds old. So, my connection wasn't using any cached response.
Knowing that max-age is specified in seconds, all I had to do was change the value to: Cache-Control: max-age=600, private, must-revalidate! There it is, now I have a 10 minute cache.
Edit: If you want to use a stale response, with the max-stale directive of the request, you shouldn't use the must-revalidate directive in the response, as I did in my webserver.

Send JSON request - JQuery analog

I need to send a JSON request similar to jQuery's ajax method.
The official documentation quote on the data parameter says:
If value is an Array, jQuery serializes multiple values with same key based on the value of the traditional setting
So I have the same situation - a key that maps to an array "parameters":[123123, {"category":"123"}]
The complete data parameter looks like
$.ajax({
url: "/api/",
data: {"parameters":[123123, {"category":"123"}], "anotherParameter":"anotherValue"}
Would you mind telling how to achieve the same functionality in Java ?
UPD:
I've made it to work with the use of gson + collections + post request.
Here're some guide lines:
Sending POST requests in JAVA.
You might also want to consider performance issues related to different kinds of json parsers
What have you tried so far and what exactly is the problem? Is it that you don't know how to create a connection, that you don't know how to serialize your objects or that you don't know how to make the thing run asynchronously?
I don't think Java has any asynchronous HTTP call methods, you need to use a regular URLConnection and run it in a separate thread. The connection itself is formed like this:
URL url = null;
URLConnection urlConnection = null;
String myURL = "http://example.com/ajax.php?foo=bar";
try {
url = new URL(myURL);
urlConnection = url.openConnection();
} catch (Exception e) {
e.printStackTrace();
return;
}
InputStream responseStream = null;
try {
responseStream = urlConnection.getInputStream();
} catch (IOException e) {
e.printStackTrace();
return;
}
Then you must use something like the AsyncTask class to make it a background job.
For converting your objects to JSON you might want to use the GSON library.

Categories

Resources