I'm trying to upload a jpeg image buffer I got back from the Camera. I know the length, but if I pass just that length to the setFixedLengthStreamingMode() routine I get errors in the logcat telling me it expected a different size. I don't know if this is a android bug (I'm running 2.3.3 on this device), or I'm supposed to add in the sizes of headers in addition to the POST data or what. I can use setChunkedStreamingMode(0) and that works fine, but I was thinking it would be nice to avoid the overhead of copying the data. I seem to always be 155 bytes off except when I arbitrarily add in 155 bytes, then it tells me I am 2 bytes off :-).
1 Answers
The URLConnection
buffers by default everything which is been written to its getOutputStream()
in client's memory until it's closed. This is mandatory because the HTTP Content-Length
response header needs to be set. But the content length is only known once all bytes have been written. This may be memory hogging when the response body is relatively large.
If you know beforehand the exact amount of bytes (note: bytes, not characters) being written, then you could use setFixedLengthStreamingMode()
to set it with exactly that amount of bytes, so that the Content-Length
header could be set much sooner and so that URLConnection
can flush more often. In your particular case, you apparently used the wrong value.
The setChunkedStreamingMode()
basically changes the transfer encoding to chunked
. This is basically one line with the byte length in hexcode and then one line of written bytes therafter and then a blank line (see also wikipedia). The last line has a byte length of 0 and so the server knows when it's the end of the body so that it doesn't have to wait for any incoming data. This allows the response body being flushed more often. You should only not set it with 0, but with a sensible value, such as 1000 or so. This way every 1000 written bytes will be sent as a new chunk.
See also:
-
2Yea, I eventually did figure out that what it wants is the total size of everything I'm going to write() (but not the size of any of the headers it will be generating for me, which would be hard to guess :-). I built a prefix and suffix buffer so I could ask the length of everything to pass to setFixedLengthStreamingMode() and it finally started working. – user1160711 Oct 28 '12 at 01:50
-
@BalusC what do you mean by `buffers by default everything... in server's memory until it's closed`? By "server's memory" do you mean the phone's memory (or more specifically the App's allocated memory heap)? I ask because what if you're uploading a large image file in a multipart/form-data, will the entire image and form-data headers be buffered in heap/phone memory, possibly leading to a OOM problem? Unless you predetermine the byte length of the form-data headers and your image, and then set it using `setFixedLengthStreamingMode()`? – Tony Chan Nov 08 '12 at 20:55
-
@Turbo: sorry, I mixed server and client in the answer. I fixed it. – BalusC Nov 08 '12 at 20:59
-
@BalusC would you have any idea why `setChunkedStreamingMode()` might not work. I need to use it, but when set my server does not receive any data just a call to my api method: http://stackoverflow.com/q/15913844/317889 – HGPB Apr 10 '13 at 03:42
-
@BalusC - you say "You should only not set it with 0, but with a sensible value, such as 1000 or so. This way every 1000 written bytes will be sent as a new chunk." I thought best practice would be to set it to 0 so that the platform default would be used. Why not 0? – ostergaard Sep 06 '13 at 08:38