Tag Archives: Android

Issues to POST streamed data to a webservice

Recently I had quite some issues with sending data via POST to a webservice from an Android app.

Let me quickly set the stage: I needed to upload data to a webservice via HTTPS. This data were dynamically generated PDF files created in the app. Since the files can become potentially large, I wanted to make sure that data would be streamed byte-wise to the webservice. I already had Volley and were using the HurlStack (which uses HttpUrlConnection).

In order to up-stream data would one needs to explicitly call either setFixedLengthStreamingMode() or setChunkedStreamingMode() on the UrlConnection. Without that the data that will go up would actually be stored in memory first. As I didn't want to take the risk that 3MB (or more) big files could blow my app with an OutOfMemoryException (especially on low-end devices, which are always short on memory!), I needed to take the safe road.

Setting up the workflow in the applications architecture was done quickly. Add some callbacks for preparing the data, counting data length and finally streaming data with an OutputStream. Worked perfectly! The problems kicked in, as I started to actually send data. I tried with fixed-length and chunked streaming mode. For fixed-length streaming mode one needs to the length of the full request body that is about to be sent. Contrary to the chunked streaming, were the connection would buffer up a certain amount of data and send it in (you guessed it!) chunks.

Unfortunatelly, chunked streaming mode wasn't supported by the webservice, so I had no alternatives left but use the fixed-length mode. But this resulted in exceptions complaining that the connection "expected 0 bytes but got 1 byte". Though, I was pretty sure that the content length used wasn't 0. Also going plain HTTP without SSL wouldn't be a real solution, I hoped maybe it's just the SSL connection causing problems. But it wasn't.

After lots of fiddling around with parameters, stepping through code and reading hidden platform classes, I came to the conclusion: something must be wrong with the HTTP(S) stack implementation in Android.

What came first to mind was OkHttp: an HTTP client with up-to-date TLS, SNI and SPDY support. No hesitation: get the library and its dependency Okio and drop everything into the project. To fully integrate OkHttp I needed to tell Volley to not use the platform's implementations. All that's needed is a subclass of HurlStack:

Without changing anything else of my implementations, the fixed-length upload streaming suddenly worked (which I take as a proof that indeed something is wrong with the platform implementations).

Setup Dagger with Eclipse

The dependency injection library Dagger by Square setup for using it with Eclipse is a bit different when not using Maven.

At the time of writing, there seem to be no complete explaination on what is needed to setup everything. I got everything working with combined information from the comments in issue 126 by staxgr and arichiardi.

  • Prepare the Eclipse project and create the directories libs and libs-compile.
  • Download the following libraries:
      • dagger-x.x.x.jar goes into the libs directory
      • dagger-compiler-x.x.x.jar goes in the libs-compile directory
    • the javawriter jar and put it into libs-compile
    • javax.inject goes into libs
  • Enable Annotation Processing and add all four libraries to the factory path of the annotation processing settings
    • Project Properties → Java Compiler → Annotation Processing
      • check "Enable project specific settings" and "Enable annotation processing"
    •  Project Properties → Java Compiler → Annotation Processing → Factory Path
      • "Add JARs..." for each downloaded jar

When starting a build, the generated files should appear in .apt_generated. This directory should be automatically configured as a source folder after annotation processing has Bern enabled.

StringEntity Doesn't Play by the Rules of Android

So here is the situation: you build up some JSON objects and pop them into a StringEntity so your HTTPClient can send the stuff to server. We know on Android, the default charset is UTF-8 and use that knowledge through out the whole application, not considering that this fact might change in some places. But it does! Using a default StringEngtity with data supposed to be encoded in UTF-8 won't give us the expected results on Android. A look into the code explains why:

// ...
if (charset == null) {
charset = HTTP.DEFAULT_CONTENT_CHARSET;
}
// ...

And guess what, HTTP.DEFAULT_CONTENT_CHARSET does not take advantage of Charset.defaultCharset() but instead is set up with "ISO-8859-1".

To get real UTF-8 data we need to do something like new StringEntity("âáàéèê", HTTP.UTF_8);.