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:
(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:
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:
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.
- the pre-Cupcake (Android SDK 1.5) way of using Handlers, which works, but is not exactly intuitive and easy to follow;
- the far preferable Cupcake way, of creating and executing inner class that overrides the AsyncTask class, which runs a resource-intensive thread in the background, provides progress updates, and reports back when finished.
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
- duplicate the above code in both Activity classes (ugly!)
- not use any Activity code in my AsyncTask (limiting!) and/or instead pass an Activity or Context in as part of its input Params, which will therefore then need to be Objects and cast down from there (reeeeeally ugly!)
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: Android, AsyncTask, dialogs, Java, multithreading
Comments:
<< Home
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.
Subscribe to Post Comments [Atom]
<< Home
Subscribe to Posts [Atom]
Post a Comment