2

I am trying to upload an image but I am getting some out of memory errors if the image file is over ~2 megs on an Android device.

File file = new File(<my image file>);
FileInputStream fis = new FileInputStream(file);
HttpClient client = new HttpClient(); 
PutMethod method = new PutMethod(myUrl); 
RequestEntity requestEntity = new InputStreamRequestEntity(fis);
method.setRequestEntity(requestEntity); 
client.executeMethod(method); 

The out of memory error happens on the executeMethod line. How can I change this to read the stream as it goes along instead of reading the entire stream into memory and causing a crash?

Sample of hte DDMS output:

07-27 10:46:24.334: DEBUG/dalvikvm(26576): GC freed 6787 objects / 522592 bytes in 119ms
07-27 10:46:24.374: DEBUG/dalvikvm(26576): GC freed 1738 objects / 196752 bytes in 33ms
07-27 10:46:24.374: INFO/dalvikvm-heap(26576): Grow heap (frag case) to 5.184MB for 253968-byte allocation
07-27 10:46:24.414: DEBUG/dalvikvm(26576): GC freed 0 objects / 0 bytes in 45ms
07-27 10:46:24.464: DEBUG/dalvikvm(26576): GC freed 3 objects / 122992 bytes in 48ms
07-27 10:46:24.474: INFO/dalvikvm-heap(26576): Grow heap (frag case) to 5.558MB for 516112-byte allocation
07-27 10:46:24.524: DEBUG/dalvikvm(26576): GC freed 0 objects / 0 bytes in 57ms
07-27 10:46:24.574: DEBUG/dalvikvm(26576): GC freed 3 objects / 254056 bytes in 46ms
07-27 10:46:24.754: INFO/dalvikvm-heap(26576): Grow heap (frag case) to 6.308MB for 1040400-byte allocation
07-27 10:46:24.824: DEBUG/dalvikvm(26576): GC freed 3 objects / 516168 bytes in 63ms
07-27 10:46:24.894: INFO/dalvikvm-heap(26576): Grow heap (frag case) to 7.808MB for 2088976-byte allocation
07-27 10:46:24.994: DEBUG/dalvikvm(26576): GC freed 0 objects / 0 bytes in 101ms
07-27 10:46:25.034: DEBUG/dalvikvm(26576): GC freed 3 objects / 1040456 bytes in 34ms
07-27 10:46:25.084: INFO/dalvikvm-heap(26576): Grow heap (frag case) to 10.808MB for 4186128-byte allocation
07-27 10:46:25.154: DEBUG/dalvikvm(26576): GC freed 0 objects / 0 bytes in 63ms
07-27 10:46:25.434: DEBUG/dalvikvm(26576): GC freed 3 objects / 2089032 bytes in 58ms
07-27 10:46:25.714: INFO/dalvikvm-heap(26576): Grow heap (frag case) to 16.808MB for 8380432-byte allocation
07-27 10:46:25.784: DEBUG/dalvikvm(26576): GC freed 0 objects / 0 bytes in 70ms
07-27 10:46:26.204: DEBUG/dalvikvm(26576): GC freed 3 objects / 4186184 bytes in 65ms
07-27 10:46:26.204: INFO/dalvikvm-heap(26576): Forcing collection of SoftReferences for 16769040-byte allocation
Cameron McBride
  • 6,650
  • 10
  • 37
  • 52

2 Answers2

4

Constructing InputStreamRequestEntity without a length causes it to buffer the data locally so it can determine a length. Since you have it as a file, use FileRequestEntity instead as it will determine the size from the file.

Devon_C_Miller
  • 15,714
  • 3
  • 40
  • 68
  • That works beautifully. I copied the FileRequestEntity and will use my own version since it will give me the perfect place to hook in for a progress bar! – Cameron McBride Jul 27 '10 at 19:41
2

The InputStreamRequestEntity class indicates that you're still using the old HttpClient 3.x.

So you have 3 options:

  1. Upgrade to HttpClient 4.0 which advertises itself with:

    Request output streams to avoid buffering any content body by streaming directly to the socket to the server.

    Not sure though if upgrading is possible on Android since it seems to be builtin.

  2. Follow the request entity streaming advice in HttpClient 3.x performance guide.

    Request streaming: The main difficulty encountered when streaming request bodies is that some entity enclosing methods need to be retried due to an authentication failure or an I/O failure. Obviously non-buffered entities cannot be reread and resubmitted. The recommended approach is to create a custom RequestEntity capable of reconstructing the underlying input stream.

    (snip, code example)

  3. Grab "plain vanilla" java.net.URLConnection, cast it to HttpURLConnection and set the streaming mode. E.g.

    ((HttpURLConnection) connection).setChunkedStreamingMode(1024);
    

    which will send the request body in chunks of 1KB. More hints here.

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452