Sunday, May 24, 2009

 

Background tasks and upfront dialogs

Android's process and threading model is fairly simple. Your application runs as a single process, but can spawn multiple threads, and is strongly encouraged to do so rather than block UI while waiting for, say, an upload or download to complete. (In fact, if you hang the main UI thread for to long, the OS will terminate your app.) You can do this one of two ways:



Here's the AsyncTask I wrote today:


private class UploadNoteTask extends AsyncTask {

protected Boolean doInBackground(Long... longs) {

//create progress dialog
publishProgress(1);

//we can't do this in the target because it's not an Activity
SharedPreferences mySettings = getSharedPreferences(Util.AppName, 0);
String currentEmail = mySettings.getString(Settings.KEY_EMAIL, "");

//try to upload the note; longs[0] is the row ID
boolean noteUploaded = mDbHelper.uploadNote(longs[0], currentEmail);

publishProgress(100);

return new Boolean(noteUploaded);
}

protected void onProgressUpdate(Integer... progress) {
showProgress("Uploading...", "Uploading data", progress[0]);
}

protected void onPostExecute(Boolean wasSuccessful) {
//get rid of the progress bar
killProgress();

//tell the user how it went
if (wasSuccessful.booleanValue()) {
showDialog("Success", "Note uploaded");
}
else { // warn user of failure
showDialog("Failure", "Could not open note: error message "
+mDbHelper.getUploadError()
+". Try again later.");
}
}
}


(Yes, obviously I'm going to move all those hardcoded strings into R.strings very soon, improve the error handling, etc.)

And here's how you call it:
new UploadNoteTask().execute(mRowId);

which I think we can all agree is not too onerous.

I have, however, run into an annoying problem. It's convenient to run this as an inner class in your Activity, as you can then call Activity-inherited methods such as the "getSharedPreferences()" method up above. However, I want to be able to upload a note both from the list of notes and the detail page for a particular note - which means I have to either



So for the moment I'm holding my nose and duplicating code. (I can't put it in a common superclass because one of my Activities inherits from ListActivity, and the other does not.) Not just the class code, either, but the "showDialog" "showProgress" and "killProgress" methods, which tell the user what's happening/happened as you upload.

At least these kinds of pop-up dialogs are very easy to work with. Here are those three methods just cited, in their entirety:


private void showDialog(String title, String message) {
AlertDialog ad = new AlertDialog.Builder(this).create();
ad.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
return;
} });
ad.setTitle(title);
ad.setMessage(message);
ad.show();
}

private void showProgress(String title, String message, int progress) {
if (mProgress==null) {
mProgress=ProgressDialog.show(this, title, message);
}
mProgress.setProgress(progress);
}

private void killProgress() {
if (mProgress!=null) {
mProgress.dismiss();
mProgress=null;
}
}


Still, my cavil above aside, I must admit it's a nice and easy way to handle background processing in a separate thread, while keeping the user semi-informed.

Labels: , , , ,


Comments:
You should implement your AsyncTask as a non inner class, and simply create an activity specific inner class that extends it. This inner class will only override the onPostExecute method and call the super version to dismiss the dialog.
 
It would be good if you can write something about merging android service with AsyncTask
 

Post a Comment

Subscribe to Post Comments [Atom]





<< Home

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]