Latest Tweets

 

Uploading Twitter profile images via Android

Last night I decided to knock out a quick app to test how straightforwardly one can upload twitter images. With the exception of one hiccup:

http://code.google.com/p/twitter-api/issues/detail?id=697

it went very smoothly.

Essentially you need to introduce two libraries into your project that are absent from Android:

  • httpmime.jar
  • apache-mime4j.jar

I used versions 4.0-beta2 and 0.5 respectively.

Here’s my very basic implementation:

//sample method for uploading a user profile image to twitter
int uploadImage(InputStream in, String type, String fileName, Credentials credentials) throws IOException {
    try {
        //convert the input stream into a byte array - this is just a convenient way
        InputStreamEntity ise = new InputStreamEntity(in, -1L);
        byte[] bytes = EntityUtils.toByteArray(ise);

        //establish the credentials
        DefaultHttpClient client = new DefaultHttpClient();
        client.getCredentialsProvider().setCredentials(new AuthScope("twitter.com", 80), credentials);

        //create the multipart entity 
        MultipartEntity entity = new MultipartEntity();
        ByteArrayBody body = new ByteArrayBody(bytes, type, fileName);
        entity.addPart("image", body);

        //assign the entity to the request and disable the Expect header
        //see http://code.google.com/p/twitter-api/issues/detail?id=697
        HttpPost request = new HttpPost("http://twitter.com/account/update_profile_image.xml");
        request.setEntity(entity);
        request.getParams().setBooleanParameter( "http.protocol.expect-continue", false ); 

        //execute the request and return the response
        HttpResponse response = null;
        try {
            response = client.execute(request);
        } finally {
            //exhaust the response
            if (response != null) {
                HttpEntity re = response.getEntity();
                if (re != null) re.consumeContent();
            }

        }
        return response.getStatusLine().getStatusCode();
    } finally {
        try {
            in.close();
        } catch (IOException e) {
            /* ignored */
        }
    }
}

I haven’t investigated properly, but disabling the “expect-continue” feature appears to cause the request entity to be read twice. So the method above depends on a helper class that provides a repeatable entity.

private class ByteArrayBody extends AbstractContentBody {

    private final byte[] bytes;
    private final String fileName;

    public ByteArrayBody(byte[] bytes, String mimeType, String fileName) {
        super(mimeType);
        this.bytes = bytes;
        this.fileName = fileName;
    }

    @Override
    public String getFilename() {
        return fileName;
    }

    @Override
    public void writeTo(OutputStream out, int mode) throws IOException, MimeException {
        out.write(bytes);
    }

    @Override
    public String getCharset() {
        return null;
    }

    @Override
    public long getContentLength() {
        return bytes.length;
    }

    @Override
    public String getTransferEncoding() {
        return MIME.ENC_BINARY;
    }

}

The Java code in this post is in the public domain.

blog comments powered by Disqus