Thursday, September 2, 2010

Asynchronous web request

Many good Android apps pull in some kind of external data to keep everything current. When making web requests for data, it is important to use asynchronous calls on a new thread so that the UI remains responsive to the user. Asynchronous calls do require a bit more code than synchronous calls, but it is a minimal amount and pays big dividends to the polish of the app.

There are 2 functions required for the call: 1) makeHTTPRequest and 2) handleHTTPResponse. Sample code for each of these is provided below.


makeHTTPRequest
private void makeHTTPRequest() {
 
 // Increment counter so we don't try infinite number of http requests
 // httpTryCount declared as a private class variable: private int httpTryCount = 0;
 httpTryCount++;
 
 // Show dialog
 // progressDialog1 declared as class variable: private ProgressDialog progressDialog1 = null;
 progressDialog1 = ProgressDialog.show(FoodDetail.this, "", "Loading...", true, false);
 
 // Fire off a thread to do some work that we shouldn't do directly in the UI thread
    Thread t = new Thread() {
         
        public void run() {
          try {
           HttpParams httpParameters = new BasicHttpParams();
           HttpConnectionParams.setConnectionTimeout(httpParameters, Constants.connectionTimeout);
           HttpConnectionParams.setSoTimeout(httpParameters, Constants.socketTimeout);
           HttpClient httpclient =  new DefaultHttpClient(httpParameters);
           String requestURL = "http://www.yoursite.com/data_feed.php?id=5";

           //Log.d(TAG,requestURL);
           HttpGet httpget = new HttpGet(requestURL);
              
           // Create a response handler
              ResponseHandler responseHandler = new BasicResponseHandler();
           strResponse = httpclient.execute(httpget, responseHandler);
             
           handler.sendEmptyMessage(0);
          } catch (Exception e) {
        //Log.d(TAG, "Error occurred during load "+ e);
        handler.sendEmptyMessage(-1);
      } //try
        } //run()
    }; //thread
    t.start();
}

handleHTTPResponse
private Handler handler = new Handler() {
 @Override
 public void handleHTTPResponse(Message msg) {
  
  // close loading progress dialog
  progressDialog1.dismiss();
  
  // If timeout, try again -- try maximum of 2 times
  if(msg.what == -1 && httpTryCount < 2) makeHTTPRequest();
  else if(msg.what == -1 && httpTryCount >= 2) {
   // If 2 failed attempts, show error message
   Builder builder = new AlertDialog.Builder(FoodDetail.this); 
            builder.setTitle("Oops");
            builder.setMessage("An error occurred. Please make sure you are connected and try again."); 
            builder.setPositiveButton("ok", null);
            builder.show();
  } else if(msg.what == 0) {
   httpTryCount = 0;
   
   // Do something with your returned data, strResponse, here
  }
  Log.d(TAG, "response handler: "+msg);
  Log.d(TAG, "response text: "+strResponse);
 };
};

The inline comments should give you an idea of what is going on in each function. (Several class variables are described in the comments.)

Enjoy your new UI-friendly asynchronous web requests.

3 comments: