HTTPResponseCache stores but never hits - android

I'm working on a application in Android which has a heavy load of web service requests.
I already have a LoginActivity in which the user introduces the username and the password and the server responses with the result and a token. Then, several activities (all of them extend from a common BaseActivity) do the heavy requests.
I have also a ServiceManager class which is responsible for all the service requests and HTTP petitions.
I'm working on implementing the HttpResponseCache to relieve this net load. Right now I have the following code:
In my LoginActivity's (the first being launched) onCreate:
//HTTP cache
try {
File httpCacheDir = new File(this.getCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; //10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);
Log.d(TAG, "Cache installed");
} catch (IOException e) {
Log.i(TAG, "HTTP response cache installation failed:" + e);
}
In my ServiceManager's httpRequest function, which is the one actually being executed every time I try to make an HTTP request:
//HTTPS connection
URL requestedUrl = new URL(uri);
httpsConnection = (HttpURLConnection) requestedUrl.openConnection();
httpsConnection.setUseCaches(true);
httpsConnection.setDefaultUseCaches(true);
httpsConnection.setRequestMethod("GET");
BufferedReader br = new BufferedReader(
new InputStreamReader(httpsConnection.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
httpResponse += line;
}
br.close();
httpsConnection.disconnect();
HttpResponseCache cache = HttpResponseCache.getInstalled();
Log.d(TAG, "Cache: " + cache);
if (cache != null) {
Log.d(TAG, "Net count: " + cache.getNetworkCount());
Log.d(TAG, "Hit count: " + cache.getHitCount());
Log.d(TAG, "Request count: " + cache.getRequestCount());
cache.flush();
}
try{
URI uriCached = new URI("<myurl>");
CacheResponse cr = cache.get(uriCached, "GET", null);
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(cr.getBody()));
while ((line = br.readLine()) != null) {
Log.d(TAG, line);
}
} catch (URISyntaxException e1) {
e1.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
}
Right now, since the server side is not ready, the URL I'm doing the requests to is always the same.
As you can see, I'm debugging a few things, these are the results:
Cache installed
Cache: android.net.http.HttpResponseCache#b3e3b6
Net count: X
Hit count: 0
Request count: X
{myJson}
As you can see, the cache is able to read my JSON when I get it via the cache.get() method, but it's never hitting.
My server side directive Cache-Control in the header of the response is:
Cache-Control:public
Cache-Control:max-age=3800
Why is the cache never hitting?
Thank you very much!

I found the problem.
I was trying to cache petitions to a PHP that returns JSON. PHP is always considered as dynamic content (and it actually is), and it's never cached.
The path to follow when trying to cache JSON y application-side only and not server-side. This way, it won't event make a request.
Best.
EDIT
Best solution for this kind of trouble is, undoubtedly, to use Volley

Related

How to handle huge data response from server in android

I am using eclipse ADT for my android development. let me explain my problem. I can receive the response from my server api, the problem is, the data is very huge and am unable to display entire response in my logcat. I used AsynTask for getting response.
DoinBackground method
getBookingResults = ServerConnection.getbookings(
BookingsActivity.this, Utils.URL + "users/"
+ "123145/" + "subscribed");
This is my Get() in separate class
public static String getData(Context ctx, String uri) {
BufferedReader reader = null;
StringBuilder sb = null;
try {
Log.d("Serverconnection URL ", uri);
URL url = new URL(uri);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(200000);
// save status code
Utils.statusCode = con.getResponseCode();
// String responseBody = EntityUtils.toString(response.getEntity());
sb = new StringBuilder();
reader = new BufferedReader(new InputStreamReader(
con.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
Log.d("server connection getData", "" + sb.toString());
return sb.toString();
} catch (SocketTimeoutException e) {
Log.d("server connection getData Error ", "" + e);
} catch (IOException e) {
e.printStackTrace();
return " ";
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
return " ";
}
}
}
return sb.toString();
}
When i am checking the response string in my logcat is shows string length 11743. The logcat is not displaying entire response
Help me out to handle huge data response
Thanks in advance
Thing is that you cannot blindly allocate all the data from server otherwise risk of OOM is very high. You should use technique similar to what android suggests with list, keep in memory only those elements visible to user. In other words, first you have to figure out what the size is or expect that size may be huge. Then load data chunk by chunk to some UI element and implement some kind of "load by scroll". In case you cannot load from the net as you scroll, perhaps due to nature of the connection, then you should load chunk by chunk and save the data to local store. And then display it chunk by chunk as described above. This is how I would do it. Sorry, not exactly the answer you look for.

How to create multiple pages on the server with socket?

while(isRunning == true) {
if (SSocket != null) {
try {
Socket socket = SSocket.accept();
PrintStream PStream = new PrintStream(socket.getOutputStream());
BufferedReader BReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String info = null;
while ((info = BReader.readLine()) != null) {
System.out.println("now got " + info);
if (info.equals("")) {
break;
}
}
String content = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Main></Main>";
PStream.println("HTTP/1.0 200 OK");
PStream.println("Content-Type: text/xml");
PStream.println("Content-Length: " + content.length());
PStream.println("");
PStream.println(content);
PStream.close();
BReader.close();
socket.close();
Thread.sleep(10);
} catch (Exception e) {
}
}
}
This code makes the server display a xml, but when I go to another page (e.g. http://10.0.0.101:39878/otherpage.html), the content is the same. How do I do to change the contents of each page and enter a 404 when it does not exist?
You have to parse the client's request to find out which page is being requested, and then send the appropriate content. The code you showed is not doing any parsing at all. In fact, it is not even reading the client's full request to begin with, only the first line of it, which is not enough. You need to read RFC 2616, which defines the HTTP protocol. And then consider NOT implementing an HTTP server manually, but use a pre-made library instead. See How to create a HTTP server in Android? for some suggestions.

Android: Quick web requests

For my application I need to have the latest data from an webpage that is hosted on a server on my local network.
So I request the latest page with a HTTP GET and when the data is received, I send another request.
With my current implementation I reach around the 100 - 120 ms per request. Is there a possibility to make this quicker because it's the same url that is requested.
For example keep the connection open to the page and grep the latest data without setting up a new connection?
This page is around the 900-1100 bytes.
HTTP get code:
public static String makeHttpGetRequest(String stringUrl) {
try {
URL url = new URL(stringUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setReadTimeout(300);
con.setConnectTimeout(300);
con.setDoOutput(false);
con.setDoInput(true);
con.setChunkedStreamingMode(0);
con.setRequestMethod("GET");
return readStream(con.getInputStream());
} catch (IOException e) {
Log.e(TAG, "IOException when setting up connection: " + e.getMessage());
}
return null;
}
Reading inputstream
private static String readStream(InputStream in) {
BufferedReader reader = null;
StringBuilder total = new StringBuilder();
try {
String line = "";
reader = new BufferedReader(new InputStreamReader(in));
while ((line = reader.readLine()) != null) {
total.append(line);
}
} catch (IOException e) {
Log.e(TAG, "IOException when reading InputStream: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return total.toString();
}
As I know there isn't an implementation like you are asking for. I've been dealing a lot with http requests and the best thing you can do is your code. There is another thing which need some attention...your connection maybe slow and depending on that connection time can be more or in some cases which I've been dealing a lot the connection's timeout isn't enough big, but that's server problem.
In my opinion you should use what you have now.

Handling HTTP Get/ Delete Android using REST

I m implementing a REST based HTTP server in Android. The server responds for GET, DELETE and POST requests. Two android devices communicate using HTTP Post (I m using a service, where a device keeps listening on a port and post to next device and this keeps going on).
I m testing the GET and DELETE using Mozilla Poster. Should I add a separate socket/port to handle the same? Because when I try now, sometimes I get timeout error or no response found. However, I am able to see server response in Logcat window. Please help me.
Code to handle GET request:
if(method.equals("GET"))
{
if(checkFileExisting())
{
BufferedReader reader = new BufferedReader(new FileReader(new File(getFilesDir()+File.separator+"script.json")));
String read;
StringBuilder builder = new StringBuilder("");
while((read = reader.readLine()) != null)
{
builder.append(read);
}
String JSONContents = builder.toString();
reader.close();
JSONObject jsonObject;
try {
jsonObject = new JSONObject(JSONContents);
String name = jsonObject.getString("name");
JSONObject stateObject = jsonObject.getJSONObject("state");
String stateValue = stateObject.getString("value");
if(name.equals(target))
{
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
response.setEntity(new StringEntity("State is:" + stateValue));
conn.sendResponseHeader(response);
conn.sendResponseEntity(response);
}
else
{
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 404, "Not Found");
response.setEntity(new StringEntity("The requested resource " + target + " could not be found due to mismatch!!"));
conn.sendResponseHeader(response);
conn.sendResponseEntity(response);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
else
{
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 404, "Not Found");
response.setEntity(new StringEntity("The requested resource " + target + " could not be found!!"));
conn.sendResponseHeader(response);
conn.sendResponseEntity(response);
}
}
The link http://www.integratingstuff.com/2011/10/24/adding-a-webserver-to-an-android-app/ has a very good example. I missed conn.close() in my code.

DefaultHttpClient change response size?

What I try to do
Hello Guys, I'm trying to create an App in which I can view the Orders the Customers gave to me. For this I created a interface on my server, on which I can send post/get/set request's. The response of the Server is in JSON-Format. (For your Information atm only dummydata is filled in)
Now when I do a get request from my app to the server, I get a response from it but it isn't complete about the half of the response I should get isn't there! :( But when I open the URL with the Get-Request in my browser, I get the full response.
Question
Like you see it can't be a server-based problem, because I also tryed via 'curl' to do this get requst, and allways got the full response.
In my App i work with the DefaultHttpClient, so I tought the Problem simply could be that there's a limit for the response but I didn't found it.
So where can I change this "response-size" and what else could be the problem why I don't get the full response! Some good code-snippets or whatever you can imagine would help!
Down here you'll find the code of the Methode which does the Get-Request.
Code
If you need more Code, just write it in the comments!
getOrders()
public void getOrders() {
Log.d("DataHandlerService", "Aufträge werden geladen");
Thread t = new Thread() {
public void run() {
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
String userid = settings.getString("userid", "uid");
Log.d("DataHandlerService", userid);
// Download-URL
String URL = "http://api.i-v-o.ch/users/" + userid
+ "/assignments.json";
Log.d("Request-URL", URL);
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response;
try {
HttpGet request = new HttpGet();
request.setURI(new URI(URL));
request.addHeader("Content-Type",
"application/x-www-form-urlencoded");
response = client.execute(request);
int statuscode = response.getStatusLine().getStatusCode();
switch (statuscode) {
case 200:
if (response != null) {
StringBuilder sb = new StringBuilder();
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity()
.getContent()));
String line;
while ((line = rd.readLine()) != null) {
sb.append(line + "\n");
}
String result;
result = sb.toString();
Log.d("Response", result);
JSONReader(result); //here the json will be generated
}
break;
case 500:
// Error-Handling
break;
}
} catch (Exception e) {
e.printStackTrace();
Log.e("DataHandler", "URLConnection-Error" + e);
}
}
};
t.start();
}
Here's the Response you asked for, like you see a part of it isn't there!:
[{"created_at":"2012-01-06T17:10:00Z","end_datetime":"2008-03-25T13:00:00Z","id":2127,"start_datetime":"2008-03-25T13:00:00Z","updated_at":"2012-01-06T17:10:00Z","title":"2127 Foobar","referee_forename":"Peter","referee_surname":"Gertsch","referee_full_name":"Peter Gertsch","category_title":"Installation - SAT","status_title":"Closed - Erfolgreich"},{"created_at":"2012-01-06T17:10:03Z","end_datetime":"2008-04-04T12:00:00Z","id":2134,"start_datetime":"2008-04-04T12:00:00Z","updated_at":"2012-01-06T17:10:03Z","title":"2134 Foobar","referee_forename":"Daniel","referee_surname":"Brunner","referee_full_name":"Daniel Brunner","category_title":"Installation - SAT","status_title":"Closed - Erfolgreich"},{"created_at":"2012-01-06T17:10:03Z","end_datetime":"2008-04-07T12:00:00Z","id":2136,"start_datetime":"2008-04-07T12:00:00Z","updated_at":"2012-01-06T17:10:03Z","title":"2136 Foobar","referee_forename":"Andreas","referee_surname":"Lutz","referee_full_name":"Andreas Lutz","category_title":"Installation - SAT","status_title":"Closed - technisches problem"},{"created_at":"2012-01-06T17:10:08Z","end_datetime":"2008-05-22T07:00:00Z","id":2144,"start_datetime":"2008-05-22T07:00:00Z","updated_at":"2012-01-06T17:10:08Z","title":"2144 Foobar","referee_forename":"Pascal","referee_surname":"Pichand","referee_full_name":"Pascal Pichand","category_title":"Installation - SAT","status_title":"Closed - Erfolgreich"},{"created_at":"2012-01-06T17:10:08Z","end_datetime":"2008-05-15T07:00:00Z","id":2145,"start_datetime":"2008-05-15T07:00:00Z","updated_at":"2012-01-06T17:10:08Z","title":"2145 Foobar","referee_forename":"Hansruedi","referee_surname":"W\u00fcrgler","referee_full_name":"Hansruedi W\u00fcrgler","category_title":"Installation - SAT","status_title":"Closed - Erfolgreich"},{"created_at":"2012-01-06T17:10:08Z","end_datetime":"2008-05-26T08:00:00Z","id":2146,"start_datetime":"2008-05-26T08:00:00Z","updated_at":"2012-01-06T17:10:08Z","title":"2146 Foobar","referee_forename":"Martina","referee_surname":"Issler","referee_full_name":"Martina Issler","category_title":"Installation - SAT","status_title":"Closed - Erfolgreich"},{"created_at":"2012-01-06T17:10:08Z","end_datetime":"2008-06-03T14:00:00Z","id":2147,"start_datetime":"2008-06-03T14:00:00Z","updated_at":"2012-01-06T17:10:08Z","title":"2147 Foobar","referee_forename":"Matthias ","referee_surname":"Kuhn","referee_full_name":"Matthias Kuhn","category_title":"Installation - SAT","status_title":"Closed - Erfolgreich"},{"created_at":"2012-01-06T17:10:12Z","end_datetime":"2008-07-07T07:00:00Z","id":2157,"start_datetime":"2008-07-07T07:00:00Z","updated_at":"2012-01-06T17:10:12Z","title":"2157 Foobar","referee_forename":"Eberhard","referee_surname":"Polatzek","referee_full_name":"Eberhard Polatzek","category_title":"Installation - SAT","status_title":"Closed - Erfolgreich"},{"created_at":"2012-01-06T17:10:13Z","end_datetime":"2008-07-11T08:00:00Z","id":2161,"start_datetime":"2008-07-11T08:00:00Z","updated_at":"2012-01-06T17:10:13Z","title":"2161 Foobar","referee_forename":"Magali","referee_surname":"Bohin","referee_full_name":"Magali Bohin","category_title":"Installation - SAT","status_title":"Closed - Erfolgreich"},{"created_at":"2012-01-06T17:10:14Z","end_datetime":"2008-07-25T08:30:00Z","id":2163,"start_datetime":"2008-07-25T08:30:00Z","updated_at":"2012-01-06T17:10:14Z","title":"2163 Foobar","referee_forename":"(Hotel Centrum Griesalp)","referee_surname":"Haltenegg Betriebs AG","referee_full_name":"(Hotel Centrum Griesalp) Haltenegg Betriebs AG","category_title":"Installation - SAT","status_title":"Closed - Erfolgreich"},{"created_at":"2012-01-06T17:10:16Z","end_datetime":"2008-08-07T09:00:00Z","id":2170,"start_datetime":"2008-08-07T09:00:00Z","updated_at":"2012-01-06T17:10:16Z","title":"2170 Foobar","referee_forename":".","referee_surname":"SAC Hollandiah\u00fctte","referee_full_name":". SAC Hollandiah\u00fctte","category_title":"Installation - SAT","status_title":"Closed - Erfolgreich"},{"created_at":"2012-01-06T17:10:16Z","end_datetime":"2009-05-07T06:30:00Z","i
Ah. Right, the problem isn't your connection or anything like that. Your service is returning an array - not an object - thus you should parse it like this:
HttpResponse response = ...
if (.. validate status ..) {
JSONArray array = new JSONArray(HttpEntityUtils.toString(response.getEntity()));
// Your JSONArray is now ready to play with.
}
And consider using an AsyncTask instead of a Thread, like this:
class AssignmentsTask extends AsyncTask<String, Void, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
final String url = "http://api.i-v-o.ch/users/" + params[0]
+ "/assignments.json";
try {
HttpResponse response = mClient.execute(new HttpGet(url));
if (response.getStatusLine().getStatusCode() == 200) {
return new JSONArray(EntityUtils.toString(response.getEntity()));
} else {
Log.w(TAG, "Error receiving assignments for " + params[0] + ", " + response.getStatusLine());
}
} catch (ClientProtocolException e) {
Log.w(TAG, "Proto: Error fetching assignments for " + params[0], e);
} catch (IOException e) {
e.printStackTrace();
Log.w(TAG, "IO: Error reading assignments for " + params[0], e);
} catch (ParseException e) {
Log.w(TAG, "Parse: Error parsing assignments for " + params[0], e);
} catch (JSONException e) {
Log.w(TAG, "JSON: Error parsing JSON for " + params[0], e);
}
return null;
}
#Override
protected void onPostExecute(JSONArray result) {
// Stuff that handles the resulting JSONObject on
// the UI-thread goes here (i.e. update View:s)
// result is null if the operation failed
}
}
And to retrieve an order for the user "116":
new AssignmentsTask().execute("116");
The response size should be given by the web server you are contacting. You could read the response size using :
httpResponse.getEntity().getContentLength()
Also, what can happen is a connection timeout, making it impossible for the client to receive all data of the response. In that case, try using a timeout that is long enough to be sure you get all the data.
If your json is too large, then it's not a good idea in a mobile context to expect all the data coming in a single request, you could then have to design a web server that could give you chunks of a response, you would then require the first chunk, then the a different one, etc..
Usually, the http protocole's partial content is the answer for that problem.

Categories

Resources