Tuesday, June 2, 2009

Android Multipart upload

So there were many posts about multipart upload in the Android Google Groups:
One guy rolled his own using HttpURLConnection, and another which strangely relied on dependencies from two different versions of the Apache HttpClient project (commons-httpclient.jar an httpcomponents-client-4.0-alpha4.); since version 3 of Apache's HttpClient was still a commons project, and the latter dependency is a version 4 alpha. The sample code contained no import statements, so it was difficult to know which version of the library was being used for what.

My confusion was deepened when I found a discussion in an Apache forum suggesting that the multipart support had not been included in the move from version 3 to version 4. There was yet another Google Groups discussion on the multipart upload using a different set of Apache libraries. I also found a discussion of the relative merits of using HttpClient versus UrlConnection in Android. I had heard before that some people have experienced odd issues with UrlConnection, which is why I switched over to HttpClient a while back (actually using an AndroidHttpClient class from the zxing project). It is not clear if the URLConnection issues have been resolved with latest code release. Either which way it is somewhat confusing that while there is some of the Apache HttpClient code in Android by default, it is not all there, or at least some of the latest parts of the library are not.

I ended up downloading the latest version of the Android HttpClient library which appeared to be version 4 beta 2 and was pleasantly surprised to find a code sample for a multi-part upload, despite the suggestion I had found that multi-part uploads had not been ported into this version. I modified this example slightly for Android and I was even more pleasantly surprised when it worked (abridged code below):

  
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("http://api.whatever.com/something");
FileBody bin = new FileBody(file);

StringBody media_entity_part = new StringBody(media_entity);

MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("bin", bin);
reqEntity.addPart("media_entity", media_entity_part);

post.setEntity(reqEntity); HttpResponse response = client.execute(post);

HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
resEntity.consumeContent();
}

The dependencies I had were the jar files that came with the latest HttpClient download:

apache-mime4j-0.5.jar
httpclient-4.0-beta2.jar
httpcore-4.0-beta3.jar
httpmime-4.0-beta2.jar

Of course I may have some overlap there too, but when it starts working you don't ask questions - at least while there doesn't seem to be a critical space issue for my android project at present.

Two feelings I come away with are:

1. Is the StringBody, FileBody class really necessary? Couldn't we just have reqEntity.addFilePart and reqEntity.addStringPart and avoid the extra line and class definitions? Seems like that just doesn't need to be seen by the API user.
2. The discussion of all this multi-part upload stuff is really scattered over the google groups for Android. I can't help but think they might get better convergence if the discussion was organised about the API itself, e.g. that questions about multi-part uploads all appeared linked with the Android docs: http://developer.android.com/reference/org/apache/http/client/HttpClient.html
MySQL, PHP and others have great embedded discussions in their docs - I don't know why Java and Ruby projects can't have similar ...