I'm trying to obtain an JSON answer type but is to big and at 50 MB Android Studio throw new Exception OutOfMemory
class MyClass extends AsyncTask<Void, Void, Void>
{
String result="";
#Override
protected Void doInBackground(Void... params){
HttpClient httpClient=new DefaultHttpClient();
String URL="http://82.79.121.114:1001/api/search/category/3,1,1";
try{
HttpGet httpGet = new HttpGet(URL);
httpGet.setHeader("Authorization", "Bearer " + AccesToken);
HttpResponse httpResponse=httpClient.execute(httpGet);
//Log.e("EROARE!!!!!!","EROARE!!!!!");
HttpEntity httpEntity=httpResponse.getEntity();
InputStream is=httpEntity.getContent();
result=convert(is);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid){
Toast.makeText(MainActivity.this,result,Toast.LENGTH_SHORT).show();
if(result.length() == 0 || result == null)
{
Toast.makeText(MainActivity.this,result.Toast.LENGTH_SHORT).show();
if(result.length() == 0 || result == null)
{
Toast.makeText(MainActivity.this,"Nu merge!!!",Toast.LENGTH_SHORT).show();
}
}
public String convert(InputStream is) throws IOException {
BufferedReader reader = null;
StringBuffer buffer = new StringBuffer();
try {
reader = new BufferedReader(new InputStreamReader(is,"UTF-8"),8192);
int read;
char[] chars = new char[1024];
while ((read=reader.read(chars)) != -1)
buffer.append(chars, 0, read);
}
finally {
if (reader != null)
reader.close();
}
return buffer.toString();
}
Your JSON object is simply too large, as most of the devices do not have such big heap. If you own the server-side, you should change the response you send to the clients and make it few separate responses, handled in a sequence.
In addition, I recommend you to rethink why you send so much data at once. It will take a very long time to load even on an average internet connection.
If indeed the OutOfMemory problem is related with the size of the data returned by your REST service then you are doing it wrong both on server and client side. A mobile application should care about users data traffic and also about their battery so instead of loading the entire JSON in one shot maybe you can split it in pages and load only the first page first. Once the user is interested in more (maybe you are using a ListView there to show those categories) then you load the next page and so on. Please see the Endless List Patter for Android Here:
https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews
Related
Some quick background. We have multiple devices running a scanner app which checks against a database to see whether an id has been scanned in or not. I can scan in with Device A as many times as I like without issue. I then pick up Device B and scan in, also as many or few times as I like. If I pick Device A back up and scan, the HttpClient will hang for approximately 60 seconds refusing to send any further requests. The code below has commented the point of failure.
// Asynchronous get request
private class aGETRequest extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
client.setKeepAliveStrategy(null);
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse httpResponse = client.execute(httpGet); //Hangs Here
HttpEntity httpEntity = httpResponse.getEntity();
InputStreamReader isr = new InputStreamReader(httpEntity.getContent());
BufferedReader buffer = new BufferedReader(isr);
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
httpEntity.consumeContent();
isr.close();
} catch (Exception e) {
e.printStackTrace();
}
httpGet.abort();
client.getConnectionManager().shutdown();
}
return response;
}
#Override
protected void onPostExecute(String result) {
results(result);
}
}
The client hangs and even snooping traffic shows no requests sent at all from Device A after the failure. You ready for the best part? If the devices are going through a Proxy server, it works. W.T.F?
Android is java 6 compat . right.
BufferedReader on java 7 makes me nervous and the while read loop appears to be whats hanging.....
I would try a different different read loop class thats solid on java 6 or i would find someone else's pattern for httpclient that's solid.
My wild guess is that your code is never getting out of the following...
while ((s = buffer.readLine()) != null)
Maybe the server is returing chunked encoding or something like that with a diff protocol ( pattern of length=0 followed by \r\n or something.
Im doing a simple http get,
I see on my result an incomplete response,
what Im doing wrong?
here the code:
class GetDocuments extends AsyncTask<URL, Void, Void> {
#Override
protected Void doInBackground(URL... urls) {
Log.d("mensa", "bajando");
//place proper url
connect(urls);
return null;
}
public static void connect(URL[] urls)
{
HttpClient httpclient = new DefaultHttpClient();
// Prepare a request object
HttpGet httpget = new HttpGet("http://tiks.document.dev.chocolatecoded.com.au/documents/api/get?type=tree");
// Execute the request
HttpResponse response;
try {
response = httpclient.execute(httpget);
// Examine the response status
Log.d("mensa",response.getStatusLine().toString());
// Get hold of the response entity
HttpEntity entity = response.getEntity();
// If the response does not enclose an entity, there is no need
// to worry about connection release
if (entity != null) {
// A Simple JSON Response Read
InputStream instream = entity.getContent();
String result= convertStreamToString(instream);
// now you have the string representation of the HTML request
Log.d("mensa", "estratagema :: "+result);
JSONObject jObject = new JSONObject(result);
Log.d("mensa", "resposta jObject::"+jObject);
Log.d("mensa", "alive 1");
JSONArray contacts = null;
contacts = jObject.getJSONArray("success");
Log.d("mensa", "resposta jObject::"+contacts);
Log.d("mensa", "alive");
//instream.close();
}
} catch (Exception e) {}
}
private static String convertStreamToString(InputStream is) {
/*
* To convert the InputStream to String we use the BufferedReader.readLine()
* method. We iterate until the BufferedReader return null which means
* there's no more data to read. Each line will appended to a StringBuilder
* and returned as String.
*/
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
Log.d("mensa", "linea ::"+line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}
i call it with:
GetDocuments get = new GetDocuments();
URL url = null;
try {
url = new URL("ftp://mirror.csclub.uwaterloo.ca/index.html");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//URL url = new URL("http://www.google.es");
get.execute(url);
edit 1
I refer to incomplete as the response that gets truncated?
please notice in below image of response how string gets truncated,
is this because of the log size?,
but the other problem is that it doesn't parse?
thanks!
I don't know if this is going to resolve your problem but you can get rid of your method and use simply:
String responseString = EntityUtils.toString(response.getEntity());
I've had exactly the same issue for the last couple of days. I found that my code worked over WiFi but not 3G. In other words I eliminated all the usual threading candidates. I also found that when I ran the code in the debugger and just waited for (say) 10 seconds after client.execute(...) it worked.
My guess is that
response = httpclient.execute(httpget);
is an asynchronous call in itself and when it's slow returns a partial result... hence JSON deserialization goes wrong.
Instead I tried this version of execute with a callback...
try {
BasicResponseHandler responseHandler = new BasicResponseHandler();
String json = httpclient.execute(httpget, responseHandler);
} finally {
httpclient.close();
}
And suddenly it all works. If you don't want a string, or want your own code then have a look at the ResponseHandler interface. Hope that helps.
I have confirmed that this is because size limit of java string. I have checked this by adding the string "abcd" with the ressponse and printed the response string in logcat. But the result is the truncated respose without added string "abcd".
That is
try {
BasicResponseHandler responseHandler = new BasicResponseHandler();
String json = httpclient.execute(httpget, responseHandler);
json= json+"abcd";
Log.d("Json ResponseString", json);
} finally {
httpclient.close();
}
So I put an arrayString to collect the response. To make array, I splitted My json format response by using "}"
The code is given below(This is a work around only)
BasicResponseHandler responseHandler = new BasicResponseHandler();
String[] array=client.execute(request, responseHandler).split("}");
Then you can parse each objects in to a json object and json array with your custom classes.
If you get any other good method to store response, pls share because i am creating custom method for every different json responses );.
Thank you
Arshad
Hi Now I am using Gson library to handle the responses.
http://www.javacodegeeks.com/2011/01/android-json-parsing-gson-tutorial.html
Thanks
Arshad
I cant' comment directly due to reputation, but in response to https://stackoverflow.com/a/23247290/4830567 I felt I should point out that the size limit of a Java String is about 2GB (Integer.MAX_VALUE) so this wasn't the cause of the truncation here.
According to https://groups.google.com/d/msg/android-developers/g4YkmrFST6A/z8K3vSdgwEkJ it is logcat that has a size limit, which is why appending "abcd" and printing in logcat didn't work. The String itself would have had the appended characters. The previously linked discussion also mentioned that size limits with the HTTP protocol itself can occasionally be a factor, but that most servers and clients handle this constraint internally so as to not expose it to the user.
I have the following code for to perform xml download via asynctask for android application targeting for android version>3. The code work pretty good if the network/internet connection is good. However, if internet connection is not good, the application will force close. I have tried throw in different kind of error catching but still unable to solve the force close on lowsy internet connection.
Anyone has any suggestion that I can try
private class DownloadWebPageXML extends AsyncTask<String, Void, InputStream> {
#Override
protected InputStream doInBackground(String... urls) {
Log.d("mylogitem", "AsyncTask started!");
InputStream content = null;
String myurl = urls[0];
AndroidHttpClient client = AndroidHttpClient.newInstance("Android");
HttpGet httpGet = new HttpGet(myurl);
try {
HttpResponse execute = client.execute(httpGet);
content = execute.getEntity().getContent();
} catch (Exception e) {
xmldownloaderror = e.getMessage();
Log.d("mylogitem", e.getMessage());
} finally {
Log.d("mylogitem", "Closing AndroidHttpClient");
client.close();
}
return content;
}
#Override
protected void onPostExecute(InputStream result) {
//do xml reader on inputstream
}
}
add a null check on variable execute, in between these two lines
HttpResponse execute = client.execute(httpGet);
if(execute == null){ return null;} // null check to see if execute is null
content = execute.getEntity().getContent();
another thing in onPostExecute, first line should check if InputStream result is null!
#Override
protected void onPostExecute(InputStream result) {
if(result == null){
Log.d("TEMP_LOG",Content is null);
return;
}
//do xml reader on inputstream
}
check and post your findings
hmm... I recommend to set connection times.
HttpClient client = new DefaultHttpClient();
HttpResponse response;
BufferedReader bufferedReader = null;
HttpParams params = client.getParams();
HttpConnectionParams.setConnectionTimeout(params, 20000);
HttpConnectionParams.setSoTimeout(params, 20000);
I have found the root cause. It is not in the dobackground.
In my case, lousy connection will sometime return not xml data type but rather loading error,
and this is passed as the inputstream to my xmlparser in postexecute.
I did not put in much error catcher in my xmlparser. xmlparser is expecting xml document but received non-xml content, thus throwing null in which i did not cover with error catcher.
Thank you for the suggestion. I have place it in my code as well.
Hi there i'm creating my first android app and i'm wanting to know what is the best and most efficient way of parsing a JSON Feed from a URL.Also Ideally i want to store it somewhere so i can keep going back to it in different parts of the app. I have looked everywhere and found lots of different ways of doing it and i'm not sure which to go for. In your opinion whats the best way of parsing json efficiently and easily?
I'd side with whatsthebeef on this one, grab the data and then serialize to disk.
The code below shows the first stage, grabbing and parsing your JSON into a JSON Object and saving to disk
// Create a new HTTP Client
DefaultHttpClient defaultClient = new DefaultHttpClient();
// Setup the get request
HttpGet httpGetRequest = new HttpGet("http://example.json");
// Execute the request in the client
HttpResponse httpResponse = defaultClient.execute(httpGetRequest);
// Grab the response
BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), "UTF-8"));
String json = reader.readLine();
// Instantiate a JSON object from the request response
JSONObject jsonObject = new JSONObject(json);
// Save the JSONOvject
ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File(getCacheDir(),"")+"cacheFile.srl"));
out.writeObject( jsonObject );
out.close();
Once you have the JSONObject serialized and save to disk, you can load it back in any time using:
// Load in an object
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(new File(getCacheDir(),"")+"cacheFile.srl")));
JSONObject jsonObject = (JSONObject) in.readObject();
in.close();
Your best bet is probably GSON
It's simple, very fast, easy to serialize and deserialize between json objects and POJO, customizable, although generally it's not necessary and it is set to appear in the ADK soon. In the meantime you can just import it into your app. There are other libraries out there but this is almost certainly the best place to start for someone new to android and json processing and for that matter just about everyone else.
If you want to persist you data so you don't have to download it every time you need it, you can deserialize your json into a java object (using GSON) and use ORMLite to simply push your objects into a sqlite database. Alternatively you can save your json objects to a file (perhaps in the cache directory)and then use GSON as the ORM.
This is pretty straightforward example using a listview to display the data. I use very similar code to display data but I have a custom adapter. If you are just using text and data it would work fine. If you want something more robust you can use lazy loader/image manager for images.
Since an http request is time consuming, using an async task will be the best idea. Otherwise the main thread may throw errors. The class shown below can do the download asynchronously
private class jsonLoad extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
#Override
protected void onPostExecute(String result) {
// Instantiate a JSON object from the request response
try {
JSONObject jsonObject = new JSONObject(result);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
File file = new File(getApplicationContext().getFilesDir(),"nowList.cache");
try {
file.createNewFile();
FileOutputStream writer = openFileOutput(file.getName(), Context.MODE_PRIVATE);
writer.write(result);
writer.flush();
writer.close();
}
catch (IOException e) { e.printStackTrace(); return false; }
}
}
Unlike the other answer, here the downloaded json string itself is saved in file. So Serialization is not necessary
Now loading the json from url can be done by calling
jsonLoad jtask=new jsonLoad ();
jtask.doInBackground("http:www.json.com/urJsonFile.json");
this will save the contents to the file.
To open the saved json string
File file = new File(getApplicationContext().getFilesDir(),"nowList.cache");
StringBuilder text = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
br.close();
}
catch (IOException e) {
//print log
}
JSONObject jsonObject = new JSONObject(text);
I'm a novice with Java and Android, but not to programming and HTTP. This HTTP GET method, mostly copied from other examples using the Apache HTTP classes, only retrieves the first few K of a large webpage. I checked that the webpage does not have lines longer than 8192 bytes (is that possible?), but out of webpages around 40K I get back maybe 6K, maybe 20K. The number of bytes read does not seem to have a simple realtionship with the total webpage size, or the webpage modulus 8192, or with the webpage content.
Any ideas folks?
Thanks!
public static String myHttpGet(String url) throws Exception {
BufferedReader in = null;
try {
HttpClient client = getHttpClient();
HttpGet request = new HttpGet();
request.setURI(new URI(url));
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sbuffer = new StringBuffer("");
String line = "";
while ((line = in.readLine()) != null) {
sbuffer.append(line + "\n");
}
in.close();
String result = sbuffer.toString();
return result;
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
No need to write you own HttpEntity-to-String code, try EntityUtils instead:
// this uses the charset the server encoded the entity in
String result = EntityUtils.toString(entity);
It looks as if the problem is with pages from a certain website starting Goo... I'm not having this problem with large pages from other sites. So the code is probably OK.