Click here to Skip to main content
15,867,308 members
Articles / Mobile Apps / Android

Painless AsyncTask and ProgressDialog Usage

Rate me:
Please Sign up or sign in to vote.
4.85/5 (14 votes)
25 Feb 2011CPOL3 min read 137.5K   3K   36   38
How to handle screen rotation when you use AsyncTask and ProgressDialog.

Introduction

In this article, I'll try to show how to create a small framework which can help you develop applications with asynchronous operations and progress dialogs without code duplication and with configuration changes handling.

Background

To avoid application freezing on complex tasks, their execution should be moved to a separate thread. As mentioned in the Android Developer reference, AsyncTask usage is the best way to do this. To wait for task completion and report about the current state, a ProgressDialog is often used.

In the perfect world, they work really well and you do not need to write a lot of code for this. Several snippets will be enough. But this fairytale ends when you start to change the configuration (at least rotate screen) because Android recreates the activity, or when you try to repeat the same functionality in different activities.

Activity cleanup

So I decided to get rid of supportive code from the activity and move it to a separate class to reuse it in the project. The activity should only create a particular task, pass it to this class, and provide a callback to process task completion. The rest of the functionality (show dialog, update progress message, close dialog, call completion handler) is common, and should be implemented in this new class AsyncTaskManager.

But besides task creation and completion handling, the activity should keep this task between recreations on configuration changes. This functionality can also be delegated to AsyncTaskManager.

Finally, the activity should contain several lines of code to do the following things:

  1. Create AsyncTaskManager on activity creation
  2. Java
    mAsyncTaskManager = new AsyncTaskManager(this, this);
  3. Let AsyncTaskManager handle the retained task and run it automatically
  4. Java
    mAsyncTaskManager.handleRetainedTask(getLastNonConfigurationInstance());
  5. Create new AsyncTask, setup AsyncTaskManager with it, and run it
  6. Java
    mAsyncTaskManager.setupTask(new Task(getResources()));
  7. Let AsyncTaskManager to retain the task
  8. Java
    return mAsyncTaskManager.retainTask();
  9. Process task completion

To reduce coupling between AsyncTaskManager and the activity, I created an interface that should be implemented by any activity which uses the same approach.

Java
public interface OnTaskCompleteListener {
    void onTaskComplete(Task task);
}

Task in parameters is initially created as an asynchronous task, so I can get results or check if this task was cancelled.

AsyncTaskManager implementation

The AsyncTaskManager is responsible now for AsyncTask and ProgressDialog management, and its logic can be implemented as follows:

  1. Create dialog on start
  2. On task assignment, somehow bind the task state (progress message) to the dialog and run the task
  3. Unbind the dialog from the task when the task should be retained and bind back on restore
  4. Cancel task on dialog cancel
  5. Dismiss the dialog on task completion
  6. Report about completion to activity (via OnTaskCompleteListener) on task cancel or complete

To organize such a communication, I introduced another interface to bind the task to AsyncTaskManager:

Java
public interface IProgressTracker {
    void onProgress(String message);
    void onComplete();
}

And implemented it:

Java
@Override
public void onProgress(String message) {
   if (!mProgressDialog.isShowing()) {
      mProgressDialog.show();
   }
   mProgressDialog.setMessage(message);
}

@Override
public void onCancel(DialogInterface dialog) {
   mAsyncTask.cancel(true);
   mTaskCompleteListener.onTaskComplete(mAsyncTask);
   mAsyncTask = null;
}

My implementation of AsyncTask has a special method to assign the IProgressTracker instance to allow to easily attach and detach a task from the rest of code that is recreated every time on configuration changes:

Java
public void setProgressTracker(IProgressTracker progressTracker) {
   mProgressTracker = progressTracker;
   if (mProgressTracker != null) {
      mProgressTracker.onProgress(mProgressMessage);
      if (mResult != null) {
         mProgressTracker.onComplete();
      }
   }
}

As you can see, AsyncTask keeps the progress message and operation result in fields and calls the specific method on attach. So if your task has completed when the activity was destroyed, on new setProgressTracker call, all callbacks will be run and the activity will receive a completion notification.

AsyncTask implementation

Custom AsyncTask implementation is pretty straightforward and looks like a standard solution except the mentioned setup method. Besides that, the onProgressUpdate method should call IProgressTracker.onProgress, and the onPostExecute method should call IProgressTracker.onComplete.

Conclusion

Now any activity can use this solution. Just add five lines of code to it and use Task from the sample code as the super class for your own tasks. You can rotate your phone as you wish in any direction, but all these configuration changes will be correctly handled.

This approach was implemented in my new application Lingo Quiz Full and Lingo Quiz Lite when it imports words from a file or request translations from Google or setup the initial set of dictionaries.

Useful links

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Beam HQ
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralGreat article Pin
Bandi Ramesh16-Feb-13 0:35
Bandi Ramesh16-Feb-13 0:35 
QuestionYou code is excellent. Pin
Dick Head5-Jan-13 12:37
Dick Head5-Jan-13 12:37 
GeneralMy vote of 4 Pin
rojy george6-Nov-12 23:46
rojy george6-Nov-12 23:46 
QuestionSlight issue? Pin
Chris Mayhew20-Sep-12 10:36
Chris Mayhew20-Sep-12 10:36 
AnswerRe: Slight issue? Pin
Mike11423-Sep-12 2:47
Mike11423-Sep-12 2:47 
GeneralAsyncTasking Pin
59632127-Aug-12 7:52
59632127-Aug-12 7:52 
GeneralMy vote of 5 Pin
Raj Champaneriya21-Jul-12 17:49
professionalRaj Champaneriya21-Jul-12 17:49 
GeneralTrouble with task.isCancelled() Pin
mmseng1-Jul-12 11:27
mmseng1-Jul-12 11:27 
GeneralRe: Trouble with task.isCancelled() Pin
mmseng1-Jul-12 16:04
mmseng1-Jul-12 16:04 
GeneralRe: Trouble with task.isCancelled() Pin
Mike1141-Jul-12 16:51
Mike1141-Jul-12 16:51 
GeneralRe: Trouble with task.isCancelled() Pin
mmseng1-Jul-12 17:02
mmseng1-Jul-12 17:02 
GeneralRe: Trouble with task.isCancelled() Pin
Mike1141-Jul-12 17:36
Mike1141-Jul-12 17:36 
GeneralRe: Trouble with task.isCancelled() Pin
mmseng1-Jul-12 17:59
mmseng1-Jul-12 17:59 
GeneralRe: Trouble with task.isCancelled() Pin
mmseng1-Jul-12 19:23
mmseng1-Jul-12 19:23 
GeneralRe: Trouble with task.isCancelled() Pin
Mike1142-Jul-12 1:39
Mike1142-Jul-12 1:39 
GeneralRe: Trouble with task.isCancelled() Pin
mmseng2-Jul-12 10:13
mmseng2-Jul-12 10:13 
GeneralRe: Trouble with task.isCancelled() Pin
Mike1142-Jul-12 22:59
Mike1142-Jul-12 22:59 
GeneralRe: Trouble with task.isCancelled() Pin
mmseng3-Jul-12 10:27
mmseng3-Jul-12 10:27 
GeneralMy vote of 5 Pin
dumb_terminal5-Apr-12 6:24
dumb_terminal5-Apr-12 6:24 
QuestionDon't bother Pin
ShawnMullen6-Feb-12 20:19
ShawnMullen6-Feb-12 20:19 
AnswerRe: Don't bother Pin
Mike1146-Feb-12 20:30
Mike1146-Feb-12 20:30 
GeneralRe: Don't bother Pin
ShawnMullen6-Feb-12 21:21
ShawnMullen6-Feb-12 21:21 
GeneralRe: Don't bother Pin
Mike1146-Feb-12 23:12
Mike1146-Feb-12 23:12 
This is really strange... Actually each time when you click "Run" button it creates and starts completely new instance of task. And it is working good at least on 1.6 emulator (I haven't checked it again on real device). Did you make a change to code or run it as is? What kind of device? What version of Android?

What I'm doing:
1. Run app on 1.6 emulator
2. Click on "Run" button
3. Wait till progress end
4. Click on "Run" button again
5. Start device rotating

And there is no crash at all.
GeneralMy vote of 5 Pin
Kevin Burandt21-Sep-11 13:49
Kevin Burandt21-Sep-11 13:49 
QuestionAnother task. Pin
Alan737511-Sep-11 7:47
Alan737511-Sep-11 7:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.