For a pleasant Android user experience it is vital for applications to actively provide feedback. When downloading images and data from the web, delays are expected. Developers should implement asynchronous connections and provide active feedback on their progress.
Throttling connections is another important technique. Android phones are mainly on 3G and Edge connections and are prone to slow connection speeds. Imagine downloading 100 images from the web simultaneously at 1 KB/second each. That certainly doesn’t make for the greatest user experience. Executing connections in smaller chunks is a much better option. For example, downloading those 100 images I mentioned earlier in chunks of 5 connections would allow for a comparable 20 KB/second rate.
Below is an example of my asynchronous HTTP connection implementation using the classes HttpConnection and ConnectionManager. It uses Apache’s HttpClient methods and allows for GET, POST, PUT and DELETE requests. A built in Bitmap decoder is also included.
To receive status updates from an HttpConnection a Handler is used (but not required). The HttpConnection will dispatch a message to the Handler at the occurrence of the following:
- HttpConnection.DID_START – The connection is removed from the ConnectionManager’s queue and started
- HttpConnection.DID_SUCCEED – The connection was successful and the response is stored in the Message instance obj field
- HttpConnection.DID_ERROR – The connection failed and the exception is stored in the Message instance obj field
Here is an implementation of a Handler:
Handler handler = new Handler() {
public void handleMessage(Message message) {
switch (message.what) {
case HttpConnection.DID_START:
text.setText("Starting connection...");
break;
case HttpConnection.DID_SUCCEED:
String response = (String) message.obj;
text.setText(response);
break;
case HttpConnection.DID_ERROR:
Exception e = (Exception) message.obj;
e.printStackTrace();
text.setText("Connection failed.");
break;
}
}
};
Now that we have a Handler we can create an HttpConnection. Here is the one line of code doing so:
new HttpConnection(handler).get("http://twitter.com/statuses/user_timeline/69177017.rss");
Sample Implementation
public void downloadTwitterIcon() {
Handler handler = new Handler() {
public void handleMessage(Message message) {
switch (message.what) {
case HttpConnection.DID_START: {
Log.d("Twitter Icon", "Starting Connection");
break;
}
case HttpConnection.DID_SUCCEED: {
Bitmap response = (Bitmap) message.obj;
icon.setImageBitmap(response);
break;
}
case HttpConnection.DID_ERROR: {
Exception e = (Exception) message.obj;
e.printStackTrace();
break;
}
}
}
};
new HttpConnection(handler)
.bitmap("http://a1.twimg.com/profile_images/398455304/gvsu-cis-avatar_bigger.jpg");
}
public void downloadTwitterStream() {
Handler handler = new Handler() {
public void handleMessage(Message message) {
switch (message.what) {
case HttpConnection.DID_START: {
text.setText("Starting connection...");
break;
}
case HttpConnection.DID_SUCCEED: {
String response = (String) message.obj;
text.setText(response);
break;
}
case HttpConnection.DID_ERROR: {
Exception e = (Exception) message.obj;
e.printStackTrace();
text.setText("Connection failed.");
break;
}
}
}
};
new HttpConnection(handler)
.get("http://twitter.com/statuses/user_timeline/69177017.rss");
}
HttpConnection.java [download]
package edu.gvsu.masl.asynchttp;
import java.io.*;
import org.apache.http.*;
import org.apache.http.client.*;
import org.apache.http.client.methods.*;
import org.apache.http.entity.*;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import android.graphics.*;
import android.os.*;
/**
* Asynchronous HTTP connections
*
* @author Greg Zavitz & Joseph Roth
*/
public class HttpConnection implements Runnable {
public static final int DID_START = 0;
public static final int DID_ERROR = 1;
public static final int DID_SUCCEED = 2;
private static final int GET = 0;
private static final int POST = 1;
private static final int PUT = 2;
private static final int DELETE = 3;
private static final int BITMAP = 4;
private String url;
private int method;
private Handler handler;
private String data;
private HttpClient httpClient;
public HttpConnection() {
this(new Handler());
}
public HttpConnection(Handler _handler) {
handler = _handler;
}
public void create(int method, String url, String data) {
this.method = method;
this.url = url;
this.data = data;
ConnectionManager.getInstance().push(this);
}
public void get(String url) {
create(GET, url, null);
}
public void post(String url, String data) {
create(POST, url, data);
}
public void put(String url, String data) {
create(PUT, url, data);
}
public void delete(String url) {
create(DELETE, url, null);
}
public void bitmap(String url) {
create(BITMAP, url, null);
}
public void run() {
handler.sendMessage(Message.obtain(handler, HttpConnection.DID_START));
httpClient = new DefaultHttpClient();
HttpConnectionParams.setSoTimeout(httpClient.getParams(), 25000);
try {
HttpResponse response = null;
switch (method) {
case GET:
response = httpClient.execute(new HttpGet(url));
break;
case POST:
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new StringEntity(data));
response = httpClient.execute(httpPost);
break;
case PUT:
HttpPut httpPut = new HttpPut(url);
httpPut.setEntity(new StringEntity(data));
response = httpClient.execute(httpPut);
break;
case DELETE:
response = httpClient.execute(new HttpDelete(url));
break;
case BITMAP:
response = httpClient.execute(new HttpGet(url));
processBitmapEntity(response.getEntity());
break;
}
if (method < BITMAP)
processEntity(response.getEntity());
} catch (Exception e) {
handler.sendMessage(Message.obtain(handler,
HttpConnection.DID_ERROR, e));
}
ConnectionManager.getInstance().didComplete(this);
}
private void processEntity(HttpEntity entity) throws IllegalStateException,
IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(entity
.getContent()));
String line, result = "";
while ((line = br.readLine()) != null)
result += line;
Message message = Message.obtain(handler, DID_SUCCEED, result);
handler.sendMessage(message);
}
private void processBitmapEntity(HttpEntity entity) throws IOException {
BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);
Bitmap bm = BitmapFactory.decodeStream(bufHttpEntity.getContent());
handler.sendMessage(Message.obtain(handler, DID_SUCCEED, bm));
}
}
ConnectionManager.java [download]
package edu.gvsu.masl.asynchttp;
import java.util.ArrayList;
/**
* Simple connection manager to throttle connections
*
* @author Greg Zavitz
*/
public class ConnectionManager {
public static final int MAX_CONNECTIONS = 5;
private ArrayList<Runnable> active = new ArrayList<Runnable>();
private ArrayList<Runnable> queue = new ArrayList<Runnable>();
private static ConnectionManager instance;
public static ConnectionManager getInstance() {
if (instance == null)
instance = new ConnectionManager();
return instance;
}
public void push(Runnable runnable) {
queue.add(runnable);
if (active.size() < MAX_CONNECTIONS)
startNext();
}
private void startNext() {
if (!queue.isEmpty()) {
Runnable next = queue.get(0);
queue.remove(0);
active.add(next);
Thread thread = new Thread(next);
thread.start();
}
}
public void didComplete(Runnable runnable) {
active.remove(runnable);
startNext();
}
}
25 Responses to “Async HTTP Connections on Android”
Leave a Reply
You must be logged in to post a comment.

After searching all over the net for an ‘easy to understand’ implementation of HtppClient I finally found this. This is really easy to understand and works like a charm. Hats Off!! Thanks a million.
thank you sooooo much for this. really helpful
Thanks mate, I was crazy looking for an easy way of doing it and this is exactly what I needed!!
really awesome
Thank you. This is what I was looking for, or at least pretty close to it
Greetings,
Great piece of code. How do you send parameters with a .post(url,data)?
I’ve tried this:
new HttpConnection(handler).post(“https://mydomain.com/login.php,”uname=”+uname+”&pword=”+pword);
But it doesn’t seem to work?
Many thanks,
Greetings, I’m also having the same problems with the POST.
How do you specify post parameters?
Indeed a very good test application. This clearly makes me understand how to do it.
Thanks a ton.
Such A nice example.. Thanks dude.
Hi… @all
help me
I first met with android application
I can a problem when creating client server
can you help me please
can you share sample project
example : application android Login in Server (php and mysql) and then view data in list view
thanks alot
Is this code example available for free use?
@Phil Feel free.
I see nothing in the code that indicates any true asynchronous downloading. All I see are messages for the start and end. If you’re downloading a file and you want to indicate the progress of download (10%, 20%, etc.) there should be a callback that gets called. This is missing from the code sample.
Hi, This helped me lot for my project. Great and simple..
Check out the awesome Android Asynchronous Http Client library, which does all of this for you automatically!
Thank you SO much for this. I would have spent days writing something that isn’t even half as good. Again, thank you!
Thank you!
Wonderful, glad i found this
The reason i was brought here, i was using Asynchttp for android to read xml and i had some issues handling UTF content and there was no proper support page for asynchttp. Your method worked perfectly well even for UTF xml
Thanks
We could also use android’s own AsyncTask
Nice work, thanks for sharing this. But I have one question: Will the threads be closed if the reqeust is completed or are the threads are only removed from the active list?
Best regards
Andy
Same for me .post(url, “data=test”);
Doesn’t appear to work
Thx, GREAT!
@Andy: to post data try this:
case POST:
List nameValuePairs = new ArrayList(2);
nameValuePairs.add(new BasicNameValuePair("id", data));
nameValuePairs.add(new BasicNameValuePair("data", moredata));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nameValuePairs);
entity.setContentEncoding(HTTP.ISO_8859_1);
entity.setContentType("application/x-www-form-urlencoded");
HttpPost httpPost = new HttpPost(url);
//httpPost.setEntity(new StringEntity(data));
httpPost.setEntity(entity);
response = httpClient.execute(httpPost);
break;
I changed the post case to this:
case POST:
HttpPost httpPost = new HttpPost(url);
// Add your data
//Split the data
String[] aData = data.split("\\&");
List nameValuePairs = new ArrayList(aData.length);
for (int x = 0; x < aData.length; x++){
String[] aVal = aData[x].split("\\=");
String name = aVal[0];
String value = aVal[1];
nameValuePairs.add(new BasicNameValuePair(name, value));
}
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
//httpPost.setEntity(new StringEntity(data));
response = httpClient.execute(httpPost);
break;
Man great code! but after I download the images bufHttpEntity.getContent() and decode into a file I don’t have permission to read the file any ideas?
Hi ,
I have used the same code to send http request tomy server in PC . It is working fine with Wifi, but if I connect to mobile internet request is not going . Can anyone suggest me a solution for this on Android.