Scheduling Background Tasks in Android

Joyce Echessa

Periodically your Android application might need to perform a task, such as checking a server for updates. The AlarmManager class can be used to schedule and execute operations that need to occur even if the application isn’t running.

The AlarmManager class enables the scheduling of repeated alarms that will run at set points in the future. The AlarmManager is given a PendingIntent to fire whenever an alarm is scheduled. When an alarm is triggered, the registered Intent is broadcast by the Android system, starting the target application if it’s not already running.

Alarm Type and Precision

There are two major alarm types, Elapsed Realtime and Real Time Clock. The first corresponds to the time since system boot and the second to UTC time. The different alarm types can be set to either wake up the device’s CPU when in sleep mode, or to fire when the device is next awake. Below is a list of the different alarm type variations available.

  • ELAPSED_REALTIME – Fires the pending intent after the specified length of time since device boot. If the device is asleep, it fires when the device is next awake.

  • ELAPSED_REALTIME_WAKEUP – Fires the pending intent after the specified length of time since device boot. It wakes up the device if it is asleep.

  • RTC – Fires the pending intent at a specified time. If the device is asleep, it will not be delivered until the next time the device wakes up.

  • RTC_WAKEUP – Fires the pending intent at a specified time, waking up the device if asleep.

Deciding on the alarm to use depends on the requirements of the task at hand. Time elapsed is suitable for setting alarms that should fire based on the passage of time, for instance regularly checking a server for changes. If you want to run a task dependent on the current locale, then the real time clock will be more suitable.

Note that elapsed time is usually the better choice. If the user changes their time settings or moves to a new locale, the change might cause some unexpected behaviour in the app. If you set a specific time for an app to sync with a server, the server could be overwhelmed when all instances of the app hit at the same time.

Setting up a recurring task

We’ll create a simple application to show the scheduling of tasks. The task we’ll schedule will be the displaying of a message using Toast (A toast provides simple feedback about an operation in a small popup). Code for this project can be found at this Git Repo.

Create a new Android project. For the view, create two buttons that will start and stop the periodic operations.

In res/layout/activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Start Alarm"
        android:onClick="startAlarm" />

    <Button
        android:id="@+id/button2"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Cancel Alarm"
        android:onClick="cancelAlarm" />

</LinearLayout>

To receive intents, we’ll set up a broadcast receiver to perform an operation when the alarm is fired. Create a class that inherits from BroadcastReceiver. In the onReceive method, which is called when the BroadcastReceiver is receiving an Intent broadcast, we will set up the code that runs our task.

In AlarmReceiver.java

package com.example.alarmexample;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context arg0, Intent arg1) {
        // For our recurring task, we'll just display a message
        Toast.makeText(arg0, "I'm running", Toast.LENGTH_SHORT).show();

    }

}

We then need to register the BroadcastReceiver in the manifest file. Declare the AlarmReceiver in the manifest file.

<application>
    .
    .
    <receiver android:name=".AlarmReceiver"></receiver>
    .
    .
</application>

To start the alarm we’ll set up the method startAlarm declared in res/layout/activity_main.xml above as the method to run when the Start Alarm button is clicked.

In MainActivity.java declare a PendingIntent and an AlarmManager variable. The PendingIntent will be used to set and cancel the alarms.

In MainActivity.java include the following instance variables.

private PendingIntent pendingIntent;
private AlarmManager manager;

In onCreate() we create an Intent that references our broadcast receiver class and uses it in our PendingIntent.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Retrieve a PendingIntent that will perform a broadcast
    Intent alarmIntent = new Intent(this, AlarmReceiver.class);
    pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
}

We then include the method that will set up the recurring alarms. Once set, the alarm will fire every 10 seconds.

public void startAlarm(View view) {
    manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
    int interval = 10000;

    manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
    Toast.makeText(this, "Alarm Set", Toast.LENGTH_SHORT).show();
}

Run the application and by clicking the “Start Alarm” button an “Alarm Set” message will appear, followed by the message “I’m running” every 10 seconds.

We used the setRepeating() method to set up a recurring alarm, but setInexactRepeating() could also be used. With setInexactRepeating() repeating alarms from multiple applications will be syncronized and fired at the same time. This will reduce the number of times the device is woken up, saving battery power. As of Android 4.4, all repeating alarms are inexact.

The setRepeating() method takes four arguments:

  1. type – alarm type, specified by the units of time to use and whether or not it should occur when the device is in sleep mode. Can be ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC, or RTC_WAKEUP.

  2. triggerAtMillis – time in milliseconds that the alarm should first fire.

  3. intervalMillis – interval in milliseconds between subsequent repeats of the alarm.

  4. operation – Action to perform when the alarm fires

Next, we’ll set up the cancelAlarm() method to stop the alarms. Include the method below in MainActivity.java

public void cancelAlarm(View view) {
    if (manager != null) {
        manager.cancel(pendingIntent);
        Toast.makeText(this, "Alarm Canceled", Toast.LENGTH_SHORT).show();
    }
}

Before running the application again, Force Stop or uninstall the app in your device or simulator. If you don’t, the previous alarm schedule will still be running. Run the application and the scheduled alarm can be stopped.

The above is a simple example showing how to use the AlarmManager to set up and cancel alarms. I use the same AlarmManager object to start and stop the alarm. This of course will not persist when the app is exited, so for a real app instead of only canceling the alarm when manager is not null (which it will be if the app was exited, no matter if the alarm is running or not), you should cancel the alarm with an equivalent PendingIntent to the one used setting it. For example you could do this instead.


Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
manager.cancel(pendingIntent);
Toast.makeText(this, "Alarm Canceled", Toast.LENGTH_SHORT).show();

Conclusion

We have looked at how the AlarmManager can be used to schedule periodic tasks. The AlarmManager is best used for tasks that need to run even when the application isn’t open. For normal timing operations that need to run during application use (ticks, timeouts, etc), it is more efficient to use the postDelayed() and postAtTime() methods of a Handler. The AlarmManager requires too much overhead to justify it being used this way.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Chris Ward

    Thanks for your comments Mutinda, more from Joyce very soon!

  • http://www.echessa.com/ Joyce Echessa

    Thanks for that. Yeah, you are right, it is a good practice to use the full qualified names, especially as projects get bigger.

  • Vikram Tiwari

    Hello Joyce,
    A small question: In a hypothetical scenario where I have multiple applications installed on an android device and these individual applications have created their respective RTC_WAKEUP alarms. Since these applications are not running when alarms are fired, I was wondering if Android gives a way of looking up (for example under Settings..) what all alarms are pending for what applications?

    How do you typically troubleshoot such applications?

    Thanks in advance,
    Vikram

    • http://www.echessa.com/ Joyce Echessa

      Hi Vikram,
      Do you mean being able to check the set alarms (and/or modify them) as an end user?

      As an end user, you are restricted by what the app developer allows you to control and see. Lets say, there is an app that has to sync with a server N number of times a day or after N number of minutes. This is usually not information made available to users, but some applications offer the user an option of cancelling automatic updates, thus stopping the alarm from running. But I have never seen an app that offers this information to users.

      So, to answer your question, if there is a way of checking all the set alarms of all applications installed on your device. No, there isn’t (none that I am aware of at least).

      I hope that answers your question. If it doesn’t let me know.