Why use background tasks?
In Android it is crucial that any long running tasks are performed on a separate thread from the main (UI) thread, otherwise your application will appear slow and unresponsive and in some cases may be terminated by the operating system.
About AsyncTask
To simplify the running of tasks on a background thread and reporting of progress back to the UI thread, Android 1.5 introduced the AsyncTask
class. For previous versions of Android you can copy the class UserTask into your application and use that instead.
AsyncTask is an abstract generic class, meaning that it must be subclassed to be used and its type signature specifies the parameters, the progress values and the final value of the task.
There is only one method on AsyncTask that must be implemented doInBackground
, this executes on the background (non UI) thread and is where you write the code to perform your long running task.
In addition there are 4 other methods which can be implemented according to your needs, all run on the UI thread:
- onPreExecute – called before the task begins, used to initialise the progress reporting UI
- onProgressUpdate – called whenever publishProgress is called from the background task, used to report progress back to the UI
- onPostExecute – called when the task completes
- onCancelled – called if a task is cancelled
About notifications
Notifications are a good way to let users know about significant events in your application, they appear in the status bar of the phone and can contain extended information which is visible to the user if they ‘pull down’ the status bar.
Ongoing notifications (those with the FLAG_ONGOING_EVENT flag set) are particularly good for reporting the progress of background tasks because they are themselves in the background from a UI point of view, provide information that something is occuring but do not stop the user from continuing to use your applicaton.
An example
As an example of the use of AsyncTasks and Notifications I have built a simple application which simulates a file download task with progress updates in a status bar notification.
The source is available on GitHub https://github.com/rupertbates/AndroidStatusBarTest
The application
The app is a simple activity with a button which triggers the background task and a list underneath, this is just so that we can test that the UI is still responsive while the background task is running.
When the user clicks on the button a notification appears in the status bar
If the user pulls down the status bar they see an extended message, showing the progress of the task. This is continually updated until the task is complete
Whilst the task is going on the UI remains responsive, we can select list items or perform any other actions
The code
There are three classes in the application:
- MyActivity – a simple activity with a button and a list
- NotificationHelper – a class to manage interaction with the status bar
- DownloadTask – the class that runs the background task
MyActivity is a straightforward Activity, all we do with it is set up the button to call the createNotification method as follows:
Button button = (Button) findViewById(R.id.notificationButton); button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { createNotification(); } });
private void createNotification() { new DownloadTask(getApplicationContext()).execute(0); }
NotificationHelper is more interesting, it encapsulates interaction with the status bar, it takes a Context in its constructor as this is needed to create notifications and has 3 methods:
- createNotification – this puts the notification into the status bar
- progressUpdate – receives progress updates from the background task and updates the status bar notification appropriately
- completed – called when the background task is complete, this removes the notification from the status bar. We could also use this to add a new ‘task complete’ notification
package com.example; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; public class NotificationHelper { private Context mContext; private int NOTIFICATION_ID = 1; private Notification mNotification; private NotificationManager mNotificationManager; private PendingIntent mContentIntent; private CharSequence mContentTitle; public NotificationHelper(Context context) { mContext = context; } /** * Put the notification into the status bar */ public void createNotification() { //get the notification manager mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); //create the notification int icon = android.R.drawable.stat_sys_download; CharSequence tickerText = mContext.getString(R.string.download_ticker); //Initial text that appears in the status bar long when = System.currentTimeMillis(); mNotification = new Notification(icon, tickerText, when); //create the content which is shown in the notification pulldown mContentTitle = mContext.getString(R.string.content_title); //Full title of the notification in the pull down CharSequence contentText = "0% complete"; //Text of the notification in the pull down //you have to set a PendingIntent on a notification to tell the system what you want it to do when the notification is selected //I don't want to use this here so I'm just creating a blank one Intent notificationIntent = new Intent(); mContentIntent = PendingIntent.getActivity(mContext, 0, notificationIntent, 0); //add the additional content and intent to the notification mNotification.setLatestEventInfo(mContext, mContentTitle, contentText, mContentIntent); //make this notification appear in the 'Ongoing events' section mNotification.flags = Notification.FLAG_ONGOING_EVENT; //show the notification mNotificationManager.notify(NOTIFICATION_ID, mNotification); } /** * Receives progress updates from the background task and updates the status bar notification appropriately * @param percentageComplete */ public void progressUpdate(int percentageComplete) { //build up the new status message CharSequence contentText = percentageComplete + "% complete"; //publish it to the status bar mNotification.setLatestEventInfo(mContext, mContentTitle, contentText, mContentIntent); mNotificationManager.notify(NOTIFICATION_ID, mNotification); } /** * called when the background task is complete, this removes the notification from the status bar. * We could also use this to add a new ‘task complete’ notification */ public void completed() { //remove the notification from the status bar mNotificationManager.cancel(NOTIFICATION_ID); } }
DownloadTask brings the whole thing together. It inherits from AsyncTask and the generic parameters specify
- the initial type passed into the execute method (Integer)
- the type progress updates are reported in (Integer)
- the type that the completed task returns (Void).
The tasks constructor creates an Notification helper which is used to interact with the status bar, this happens in the 3 methods which run on the UI thread
- onPreExecute – called before the task starts, this creates the notification
- onProgressUpdate – receives progress updates from the background thread and updates the notification
- onPostExecute – called when the task completes , removes the notification from the status bar
The doInBackground
method is the method which runs on the background thread, this is where we would do the real work of the task reporting progress back to the UI thread by calling publishProgress
. In this example I am just looping for 10 seconds, reporting progress every second.
package com.example; import android.content.Context; import android.os.AsyncTask; public class DownloadTask extends AsyncTask{ private NotificationHelper mNotificationHelper; public DownloadTask(Context context){ mNotificationHelper = new NotificationHelper(context); } protected void onPreExecute(){ //Create the notification in the statusbar mNotificationHelper.createNotification(); } @Override protected Void doInBackground(Integer... integers) { //This is where we would do the actual download stuff //for now I'm just going to loop for 10 seconds // publishing progress every second for (int i=10;i<=100;i += 10) { try { Thread.sleep(1000); publishProgress(i); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } protected void onProgressUpdate(Integer... progress) { //This method runs on the UI thread, it receives progress updates //from the background thread and publishes them to the status bar mNotificationHelper.progressUpdate(progress[0]); } protected void onPostExecute(Void result) { //The task is complete, tell the status bar about it mNotificationHelper.completed(); } }
Hope this is useful to someone, if you have questions let me know.
thanks buddy
this is a very helpful explaination.
Thanks…
Informative article…Thanks
you are the best ¡
Cool! Been searching for tutorials all day and this is one of the best out there!
thnx dude…itz very helpful for my application..:)
Hey, just made ma day
Thanx man……..
Brilliant! Very helpful, and well explained (even the ASync task bit for noobs!) Much appreciated!
10x!
Thread.sleep(1000);
makes the download slow.
how can i fix it?
thx
just make it 100
Hey thank you for the very useful tutorial! Just wondering, is it possible to include a progress bar as well in the notifications in your implementation?
[…] understand from this link to create a notification in the android status bar. However, if my content title is too long, the […]
[…] understand from this link to create a notification in the android status bar. However, if my content title is too long, the […]
It is very useful to me dude, it is very informative one…
publishProgress() not gettng integer as value
Man!! You are awesome!!! this is great! Thanks a lot for sharing!!
Thank you 😀
thanks a lot for share this code.
God bless you
Hay That was a great example of asyntask but how could you recode it using Handlers
Thanks – but I need an additional idea to make it run: in the AsyncTask I need access to public variables that keep changing. Although I declared them public in the MainActivity and in the same package they are not visible in the AsyncTask. What can I do?
how to use notification bar without use of button click …..
[…] I’m using this tutorial on AsyncTask with a task and a notification: https://eliasbland.wordpress.com/2011/03/11/an-example-of-how-to-run-a-background-task-and-report-pr… […]