Ahmed Hussein
Ahmed Hussein

Reputation: 429

Android HttpClient Outof memory Error (xml data)

I am having a problem to read large data from xml web service the xml file is about 5.5Mb and the code crashes and raise out of memory error

Here is my function

 private static HttpResponse executePostHttpRequest(String baseUrl,
  String names[],
  String values[]) throws ClientProtocolException,
  IOException {
final HttpClient client = newHttpClientInstance();
HttpPost request = new HttpPost(baseUrl);

boolean haveData = (names != null) && (values != null);

// if we have data, form it into request
if (haveData) {

  List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(values.length);

  for (int i = 0; i < values.length; i++) {
    nameValuePairs.add(new BasicNameValuePair(names[i], values[i]));
  }

  try {
    request.setEntity(new UrlEncodedFormEntity(nameValuePairs, "utf-8"));
  } catch (UnsupportedEncodingException e) {
    request.setEntity(new UrlEncodedFormEntity(nameValuePairs));
  }
}

request.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
// return response created by executing this request
return client.execute(request);

}

and here is my dumb

        12-05 23:30:31.813: I/dalvikvm-heap(443): Forcing collection of SoftReferences for 4842758-byte allocation
    12-05 23:30:31.964: D/dalvikvm(443): GC freed 0 objects / 0 bytes in 143ms
    12-05 23:30:31.964: E/dalvikvm-heap(443): Out of memory on a 4842758-byte allocation.
    12-05 23:30:31.964: I/dalvikvm(443): "pool-1-thread-3" prio=5 tid=35 RUNNABLE
    12-05 23:30:31.977: I/dalvikvm(443):   | group="main" sCount=0 dsCount=0 s=N obj=0x44f92608 self=0x3d92a0
    12-05 23:30:31.977: I/dalvikvm(443):   | sysTid=460 nice=0 sched=0/0 cgrp=default handle=3901200
    12-05 23:30:31.984: I/dalvikvm(443):   at java.lang.AbstractStringBuilder.enlargeBuffer(AbstractStringBuilder.java:~97)
    12-05 23:30:31.984: I/dalvikvm(443):   at java.lang.AbstractStringBuilder.append0(AbstractStringBuilder.java:155)
    12-05 23:30:31.984: I/dalvikvm(443):   at java.lang.StringBuilder.append(StringBuilder.java:216)
    12-05 23:30:31.984: I/dalvikvm(443):   at com.XXXXXXXXX.api.HttpUtils.convertStreamToString(HttpUtils.java:308)
    12-05 23:30:31.993: I/dalvikvm(443):   at com.XXXXXXXXX.api.HttpUtils.responseToString(HttpUtils.java:331)
    12-05 23:30:31.993: I/dalvikvm(443):   at com.XXXXXXXXX.api.HttpUtils.executeRequest(HttpUtils.java:208)
    12-05 23:30:31.993: I/dalvikvm(443):   at com.XXXXXXXXX.api.HttpUtils.access$0(HttpUtils.java:188)
    12-05 23:30:31.993: I/dalvikvm(443):   at com.XXXXXXXXX.api.HttpUtils$3.run(HttpUtils.java:171)
    12-05 23:30:31.993: I/dalvikvm(443):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)    
12-05 23:30:31.993: I/dalvikvm(443):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
12-05 23:30:31.993: I/dalvikvm(443):   at java.lang.Thread.run(Thread.java:1096)
12-05 23:30:33.024: D/HttpUtils(443): Throwable: java.lang.OutOfMemoryError
12-05 23:30:35.383: D/HttpUtils(443): Throwable: java.lang.OutOfMemoryError

Any advice?

Upvotes: 1

Views: 915

Answers (2)

Kurtis Nusbaum
Kurtis Nusbaum

Reputation: 30825

Try reading the actual input stream directly. This will allow you to use an XMLPullParser, meaning you won't have to keep the entire XML file in memory while you're parsing it. Pull parsing works by parsing the element as soon as you get it and relying on state (like a SAX parser) to keep track of where you are. It's a need concept that lets you think of you xml file as a stream of XML tags coming in.

You'd wanna do something like the following:

URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
  InputStream in = new BufferedInputStream(urlConnection.getInputStream());
  XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
  factory.setNamespaceAware(true);
  XmlPullParser parser = factory.newPullParser(); 
  parser.setInput(new InputStreamReader(in));
  XmlUtils.beginDocument(parser,"results");
  int eventType = parser.getEventType();
  do{
    XmlUtils.nextElement(parser);
    parser.next();
    eventType = parser.getEventType();
    if(eventType == XmlPullParser.TEXT){
      Log.d("test",parser.getText());
    }
    //...Handle other types of events...
  } while (eventType != XmlPullParser.END_DOCUMENT) ;
}
finally {
  urlConnection.disconnect();
} 

I cobled that example together from this tutorial and this documentation. I've haven't actually tried it to see if it works though.

Upvotes: 0

blindstuff
blindstuff

Reputation: 18348

Zip the xml, text compresses very well, I had a similar issue (JSON instead of XML), not only did it solve my issues with memory, it also made the app a million times faster.

In my specific case, the JSON string changed from 5 Mb, to 200kb.

Look in this direction: Gzip in Android

Upvotes: 2

Related Questions