Monday, May 2, 2011

HttpConnection with AsyncTask and Loading Dialog

One of the common tasks in Android is to make an Http connection to retrieve some information for the app to use. In a lot of areas, internet speed is slow; and we should always assume a slow connection. If we do a synchronous Http connection (calling from the UI thread), we will block user activity if the http response does not return immediately. When users click on anywhere on the screen, there would be no response because the app is waiting for the Http connection to return on the UI thread. Users may assume the app is frozen. In addition, the ANR dialog box may show up.

The solution to this is to sponsor another a background thread to do the Http connection, without blocking the UI thread. We can achieve this by extending the AsyncTask. It also makes sense to put a cancel-able loading dialog box to show that the task is running. We want it to be cancel-able because we do not want to block the UI thread.

The following shows an example for download an image:

private class LoadImageTask extends
AsyncTask<String, Integer, Bitmap> {

private Activity mActivity;
private ProgressDialog mDialog;

public LoadImageTask(CustomActivity activity) {
mActivity = activity;
}

protected void onPreExecute() {
if (mActivity != null && mActivity.getIsActive()) {
mDialog = new ProgressDialog(mActivity);
mDialog.setMessage("Loading...");

mDialog.setCancelable(true);

OnCancelListener ocl = new OnCancelListener() {
public void onCancel(DialogInterface arg0) {
LoadImageTask.this.cancel(true);
}
};

mDialog.setOnCancelListener(ocl);
mDialog.show();
}
}

@Override
protected Bitmap doInBackground(String... m) {

    if(m != null && m.size() > 0) {
Bitmap image = HttpConnect.downloadImage(m[0]);
}
return image;
}

@Override
protected void onProgressUpdate(Integer... progress) {
}

@Override
protected void onPostExecute(Bitmap image) {

if (mActivity != null && mActivity.getIsActive() && mDialog != null) { mDialog.dismiss();
}

   if(im != null && image != null) {
     iv.setImageBitmap(image);  // iv is the ImageView object
   }

}



}

Notes:

CustomActivity extends Activity. It has a private variable called mActive is keep track of if the activity is active.  This is needed to keep track of if the activity is still on. When an AsyncTask returns, it is easy for a user to be ten activities ahead of the activity that started the AsyncTask.  In this case, when the dialog dismisses, you may get "java.lang.IllegalArgumentException: View not attached to window manager".

The following is the implementation of the CustomActivity. To use it, you will want your activities to extend it.


public class CustomActivity extends Activity {

protected boolean mActive = false;

public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
    mActive = true;
}

protected void onPause() {
        super.onPause();
        mActive = false;
    }
  
    public boolean getIsActive() {
     return mActive;
    }

    ...
}


To use the class, you will call the following in your Activity:

  new LoadImageTask(this).execute(YOUR_IMAGE_URL);

No comments:

Post a Comment