Android AsyncTask template

Any meaningful GUI application needs to employ multiple threads, otherwise it is very likely to lock while doing any I/O operations - leaving bad impression on the user. Same is true for Android apps. In fact, android framework prompts user to close the app if it doesn’t respond in 10 seconds or so. So it’s absolutely essential to perform any task - that has even a remote possibility of taking a bit longer - in a background thread.

Fortunately Android framework has some useful constructs built into the framework that make our job relatively easy while doing multithreaded GUI programming. android.os.AsyncTask is one of them.

The basic steps to make your app multithreaded using AsyncTask are as follows:
1. Identify the code segment that you want to execute in background thread. (for e.g. code that does network i/o, bulk file transfer on local disk, etc)

2. Model it as an AsyncTask object.
(Subclass the AsyncTask object and put your code segment in the doInBackground(…) method)

3. Figure out what parameters you have to pass to the task, the result that the task should return and how to handle the exception in case something goes wrong.

This is pretty simple, but the third step gets bit complicated as your app grows and there are multiple asynchronous tasks that you want to code in.

When I was faced with this problem during the development of CuTewit, I stumbled through some steps. After a while I managed to create a template for modelling with AsyncTasks. In my second app - ReaderScope - the same template worked very nicely. ReaderScope has over 50 different tasks that are run on background thread at one time or another. The template I use, has made it pretty easy to add new AsyncTasks.

In this post, I want to share that template with you. I have written a small example app that demonstrates the use of the template. Download source tarball and apk to try it yourself.

Here is the source code of AppTask.java (the derivative of AsyncTask) for discussion.

package com.altcanvas.asynctemplate;  
  
import android.os.AsyncTask;  
  
**public** **class** AppTask **extends** AsyncTask<AppTask.Payload, Object, AppTask.Payload>  
  
{  
    **public** **static** **final** String TAG = "AppTask";  
  
    **public** **static** **final** **int** APPTASK_1 = 1001;  
    **public** **static** **final** **int** APPTASK_2 = 1002;  
  
    /*  
     * Runs on GUI thread  
     */  
    **protected** **void** onPreExecute() {  
    }  
  
    /*  
     * Runs on GUI thread  
     */  
    **public** **void** onPostExecute(AppTask.Payload payload)  
    {  
        **switch**(payload.taskType) {  
  
        **case** APPTASK_1:  
            AsyncTemplateActivity app =  
                (AsyncTemplateActivity) payload.data[0];  
  
            **if**(payload.result != null) {  
  
                // Present the result on success  
  
                **int** answer = ((Integer) payload.result).intValue();  
                app.taskStatus.setText("Success: answer = "+answer);  
  
            } **else** {  
                // Report the exception on failure  
  
                String msg = (payload.exception !=null) ?  
                                payload.exception.toString() : "";  
                app.taskStatus.setText("Failure: error ="+msg);  
            }  
  
            **break**;  
  
        **case** APPTASK_2:  
            **break**;  
        }  
    }  
  
    /*  
     * Runs on GUI thread  
     */  
    **public** **void** onProgressUpdate(Object... value)  
  
    {  
        **int** type = ((Integer) value[0]).intValue();  
  
        **switch**(type) {  
  
        **case** APPTASK_1:  
            AsyncTemplateActivity app = (AsyncTemplateActivity) value[1];  
            **int** progress = ((Integer) value[2]).intValue();  
            app.progressBar.setProgress(progress);  
            **break**;  
  
        **case** APPTASK_2:  
            **break**;  
        }  
  
    }  
  
    /*  
     * Runs on background thread  
     */  
    **public** AppTask.Payload doInBackground(AppTask.Payload... params)  
  
    {  
        AppTask.Payload payload = params[0];  
  
        **try** {  
            **switch**(payload.taskType) {  
            **case** APPTASK_1:  
  
                // extract the parameters of the task from payload  
  
                AsyncTemplateActivity app =  
                    (AsyncTemplateActivity) payload.data[0];  
                **int** numSteps = ((Integer) payload.data[1]).intValue();  
  
                **if**(numSteps < 0) **throw** **new** AppException("Invalid input");  
  
                // perform the task  
  
                **int** progress = 0;  
                **for**(; progress < numSteps; progress++) {  
                    **try** {  
                        // pretend to work for 1 second  
  
                        Thread.currentThread().sleep(1000);  
                    } **catch**(InterruptedException ie) {  
                        **break**;  
                    }  
                    publishProgress(**new** Object[] {  
                            **new** Integer(APPTASK_1), app, progress});  
                }  
  
                publishProgress(**new** Object[] {  
                        **new** Integer(APPTASK_1), app, progress}); 

                // Return result of the task  
                payload.result = **new** Integer(42);  
                **break**;  
  
            **case** APPTASK_2:  
                **break**;  
            }  
        } **catch**(AppException ape) {  
            payload.exception = ape;  
            payload.result = null;  
        }  
  
        **return** payload;  
    }  
  
    **public** **static** **class** Payload  
    {  
        **public** **int** taskType;  
        **public** Object[] data;  
        **public** Object result;  
        **public** Exception exception;  
  
        **public** Payload(**int** taskType, Object[] data) {  
            **this**.taskType = taskType;  
            **this**.data = data;  
        }  
    }  
}  

code syntax highlighting by GVIM,

Let’s go over different aspects of this code.

What is Payload?
To simplify the management of passing parameters and carrying result/exception back, we create a special object called Payload. Payload carries four entities - the type of the AsyncTask (int taskType), parameters to the task (Object[] data), result of the task (Object result), exception that took place during the task (Exception exception).

Note the signatures of doInBackground and onPostExecute. The same payload object is passed around.

How do you start a new task?

**new** AppTask().execute(**new** AppTask.Payload(  
    AppTask.APPTASK_1,  
**    new** Object[] { AsyncTemplateActivity.**this**,  
**    new** Integer(numSteps) })); 

     

[You can find it in AsyncTemplateActivity.java in the sample app]

How do you define a new async task?
You don’t have to create another AsyncTask derivative object. Just define a new taskType, e.g. APPTASK_2 in AppTask.java. Create a switch case for that taskType in each of ‘doInBackground’, ‘onPostExecute’, ‘onProgressUpdate’. Depending upon the nature of the tasks, the contents of payload.data will vary. Since this data is passed as generic Object[], you can pass around any types of objects that suite the task’s needs. On the other hand, you have to be careful to not type cast them to wrong classes.
[We loose Java’s static type checking by defining params and result as generic ‘Object’s. But it saves us from repetitively defining similar AsyncTask derivatives]

How is the progress of the task updated?
When you call publishProgress(…), it results in a call to onProgressUpdate(…) which is running in the GUI thread. Here, you can manipulate any widget like progress bar to indicate the task progress.

This may not be the only way to code AsyncTask, but it certainly has worked for me - not just for one, but for two sizeable projects. Before this, it used to be pretty cumbersome to define a new task.

You can download the source code and use it in your app if you like.

Any comments and suggestions are welcome.


Flattr this

Ads:


Home


Archive

2018

Violet end of spectrum

Vipassana Meditation

Why gamers like pixelated games

2017

Collecting Vs Hoarding Netflix

Game Design tip for Programmers - Less Automation

Review Ghost In The Shell - The blinds scene

Why Electron is the best development platform?

Project Dialog

2016

Don't Panic

The Entanglement Pattern

The flying cars analogy

Road Trip of Atlantic Canada

Having done attitude

2015

Before fixing performance issues

No Exams, Yes Video games

Podcasts Français

2014

Quotable Quotes

Conned?!

2013

Uruguay's President

New rules for Formula 1

Software Engineering Code of Ethics and Professional Practice

Something's missing

2012

Coffeescript: To switch or not to switch

Water from air

The single most reason that keeps me using Vim

Time travel fiction

When your git branch diverges from your remote

Something like Olivia - John Mayer

Online courses - New technology, Old rules

Kelsey Grammer is spectacular

Why Patriotism doesn't make sense

Why sea steading is important to pursue?

Prometheus

Rolling back latest git commit

Google Lunar X Prize

iTunes Download stopped (err =9006)

Good essay on user centric software design

Why we need to explore Seasteading?

2011

Master pieces from screen

How to write interactive CLI utility in node.js

The Gods Themselves by Isaac Asimov

Why OpenGL ES is so hard?

How to print stack trace anywhere in Javascript

It's not fair to compare Android with Internet Explorer

How to debug WebWorker threads?

Why can't I criticize Government if I don't vote? I sure can.

Elon Musk quote

Don't label yourself

Why the hi-tech minds are writing Social apps?

Truce with exercise

JavaScript is the next C

Ever growing todo list is a good sign for creative projects

Lesser women in tech... So what?

HTML5 offline cache - use swapCache carefully

How Wikipedia and Flattr can together change the World

2010

Discovering LastPass

Functional programming in Javascipt using Underscore.js

Youtube ETA - Chrome extension

Why secure airports when it's planes that fly?

Mac book red light audio jack problem on Linux

How to save HTML5 canvas image to Google App Engine

Why don't they publish eBooks for free but with embedded ads?

Silicon Valley and Hi-tech

Reality distortion field around

Indirect experiments

Music sharing

ReaderScope 2.0.6 - Find Comments

ReaderScope 2.0

predictably irrational

ReaderScope upcoming changes

Tuxmac

Why "Open" is not the first concern of user?

Mutt, Gmail, gdata, notify-send: A Perfect Email solution

Are you the Matt Damon of your game?

ReaderScope 1.9 - OAuth

New app "Find Comments"

@font-face-lift

ReaderScope 1.8.{2,3} - new authentication and global share

Portable apps for iPhone, Android, Pre, n900 - Can Processing.js help?

ReaderScope 1.8.1 - rethinking features

ReaderScope 1.8 - Random

Android fragmentation : How big a deal is it?

on Dropbox

iLikeIt

ReaderScope v1.7 - Widget, new Icons and .... Ads

on Git: tips for SVN users and Git in Dropbox cloud

How to do an online IDE for Android app development

Anti Asserts

Bono's top ten list

Make Android speak your Twits with "TwitSpeak"

2009

Reality of colors

Talking Twitter client

ReaderScope 1.5 - quicker, better, prettier

Preview android.R.drawable.* images

Is definition of "Evil" changing?

on Music: Battle Studies

ReaderScope 1.4 (with a Theme Pack)

On Chrome OS

Black on White

Android AsyncTask template

The AND-OR problem of laptop and mobile phone

ReaderScope v1.3.3 - offline podcasts

ReaderScope v1.3.2 - Social Channels

ReaderScope v1.3 - Beyond Google Reader

Frets on Fire for Maemo - Update

ReaderScope 1.2.7 - Podcasts, Expanded View

Sprint HTC Hero problems with ReaderScope

ReaderScope 1.2.3 - Search

ReaderScope 1.2.1 - Auto Login

ReaderScope v1.2

ReaderScope 1.1.3 - SDCard storage

Crash report for Android App

Wifi and Battery

ReaderScope 1.1.2

ReaderScope 1.1.1 quick-n-easy features

ReaderScope 1.1 - Social Beacons

ReaderScope 1.0.2 - making deep cache simple

ReaderScope 1.0.1

ReaderScope 1.0

Detecting HTC magic on Fedora

ReaderScope beta4 - offline fun

ReaderScope beta3 - Tweet the news

ReaderScope Beta2

ReaderScope beta1 is out

Intercepting Up/Down keys from bash script

Makeshift XML beautifier in python

HTC Magic (Indian version) - expectations and facts

using android AsyncTask

Android development with Vim + Eclim

Cutewit (preview)

Einstein's Dreams

Preprocessing the GUI

Evas + Inkface in v0.2.5

easy source

FoF - PyOpenGL = miniFoF (possibly for n810)

FoF update

Twitter client with inkface-pygame v0.2.2

Frets on Fire on Maemo 5 (Fremantle)

Static IP configuration on Fedora 10

Inkface+pygame v0.2.0

Smooth scrolling with Inkface+pygame

Inkface v0.2 update and automated GUI testing

Testing Android (Koolu Beta 3) on Openmoko Freerunner

Clutter animation paths with Inkscape+Inkface (v0.1.3)

Turning a page

Planning Inkface v0.2

Debian repository on Google App Engine

Inkface + Clutter

Inkface v0.1.2, Twitter-inkface client

2008

Inkface update

Debugging python reference counts

Paul Graham nails it again!

Fedora 10 on MacBook 2,1

A great essay

Thanksgiving at Crater Lake

Digital SLR buyer's guide

more fun with notify-send

(k)ubuntu 8.10 - not ready for my home yet

Migrating to Google App Engine

Android opened - first looks inside

Has it started?

Inkface v0.1

Musical discovery of the week

Die Berlin-Affäre

aus Berlin

Inkface - SVG based GUI design

Script fun

Visualizing source code

OpenMoko photo tour

New connection with the past

George Carlin - favorite clip

temperature

80-20 rule

Python fun

OSiM'08 Berlin, Germany

Of games

"Wine" tasting

Today's slashdot and open source

Cost of Open Source

Lions for Lambs

Ubuntu reviewed

Flickr uploads from n810

Cringely and Paul Graham

Accelerometer brainstorming

Clutter Webkit

OSiM USA 2008 - Day 2

OSiM USA 2008 - Day 1

Google code

Gr8 commercial

OSiM USA 2008, see you there

OpenMoko, Android and a great hacking post

two great videos

Blog from nokia tablets

2007

cool n770 hack

Picasso

Colbie Caillat

Firefox 3 is brilliant!!!

XML RPC server inside apache mod_python

best effort technologies

coding Monalisa

formula of a horror movie

next desktop jump

The "Screen"

Nice review article on virtualization technologies

Once again... a quote from 'Troy'

Story of a random number

quotes from George Carlin

"from time import sleep"

Sea surfing under the Golden Gate

Trip videos

2006

across two hours

What I read...

How do I backup to Amazon S3 storage service

Stranger than fiction

Gas prices... seems like big scam

Another nice quote

Hilarious nerd comment

Programming & Painting

Why do we like fiction?

Troy

If Harry Potter were a computer hacker ...

Gentoo, XGL, HGG

Henry Ford

VI - A capable IDE

New blog

Safari Bookshelf

2005

Back to the L4

Quotes

GCC 2.95 rpms

repeat (ps | grep) = filtered top

Halo fixed on ATI Mobility Radeon 9000

DirectX Installation Problem

Warning: const is a keyword in ANSI C

Not much on L4 front

Last two weeks

GRUBing

Stumbled on HURD

Installed HURD console

Make problem solved

2004

Handy way to create stack trace