2

I sometimes get an OutOfMemoryError when posting a large file in Android. This is the code I'm using. Am I doing something wrong?

HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setDoInput(true);
con.setDoOutput(true);
ostream = new DataOutputStream(con.getOutputStream());
byte[] buffer = new byte[1536];
int count;
while ((count = fileInput.read(buffer)) != -1) {
    ostream.write(buffer, 0, count); // This sometimes causes OutOfMemoryError
}
ostream.flush();

Would calling ostream.flush() inside the while loop do any good?

hpique
  • 119,096
  • 131
  • 338
  • 476

2 Answers2

4

If you do it like that, the whole POST must be buffered in memory. This is because it needs to send the Content-Length header first.

Instead, I think you want to use the Apache HTTP libraries, including FileEntity. That will let it figure out the length before reading the file. You can use this answer as a starting point. But the second parameter to the FileEntity constructor should be a mime type (like image/png, text/html, etc.).

Community
  • 1
  • 1
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • Thanks Matthew. Is this POST behavior documented somewhere? In my particular case I don't know the content-length beforehand because its encoded on the fly, but I will look into FileEntity anyway. – hpique Dec 15 '10 at 21:38
  • @hgpc, it's fundamental to how HTTP works. Headers always go before the request or response. The server can either either use the `Content-Length` header (recommended) or disconnect at the end of the response. However, the client has to use `Content-Length`, because it's staying on the line until it gets the response. See this [example POST session](http://www.jmarshall.com/easy/http/#postmethod). – Matthew Flaschen Dec 15 '10 at 21:42
  • @Matthew Base64. Unfortunate requirement on the server-side, but I have to deal with it anyway. – hpique Dec 15 '10 at 21:46
  • But is it (originally) a Base64 file on disk, a String, or what? There are other [types of HttpEntity](http://developer.android.com/reference/org/apache/http/entity/AbstractHttpEntity.html) you should look at. – Matthew Flaschen Dec 15 '10 at 21:47
  • @Matthew Originally it's a binary file. I'm thinking of creating the Base64 conversion on disk first, and then send it to the server with FileEntity. – hpique Dec 15 '10 at 21:49
  • @hgpc, that seems like a reasonable option. – Matthew Flaschen Dec 15 '10 at 21:53
2

HTTP connection is fine, but HTTPS will trigger Out of Memory error because there is a bug in HttpsURLConnectionImpl.java in Android 2.3.4 (verified on my tablet), and it's fixed in Android 4.1 (I have checked the source code).

By the way, he should avoid buffering the whole POST data in RAM by adding "con.setChunkedStreamingMode(0);" immediately after "con.setDoOutput(true);" statement.

Bob Cheng
  • 81
  • 7