This tutorial describes how to schedule tasks in Android with the JobScheduler API.

1. Scheduling tasks

1.1. Options for scheduling

If you have a repetitive task in your Android app, you need to consider that activities and services can be terminated by the Android system to free up resources. Therefore you can not rely on standard Java schedule like the TimerTasks class.

The Android system currently has two main means to schedule tasks:

  • the (outdated) AlarmManager

  • the JobScheduler API.

Modern Android applications should use the JobScheduler API. Apps can schedule jobs while letting the system optimize based on memory, power, and connectivity conditions.

1.2. The job scheduler API

The Android 5.0 Lollipop (API 21) release introduces a job scheduler API via the JobScheduler class. This API allows to batch jobs when the device has more resources available. In general this API can be used to schedule everything that is not time critical for the user.

1.3. Advantages of the job scheduler API

Compared to a custom SyncAdapter or the alarm manager, the JobScheduler supports batch scheduling of jobs. The Android system can combine jobs so that battery consumption is reduced. JobManager makes handling uploads easier as it handles automatically the unreliability of the network. It also survives application restarts. Here are example when you would use this job scheduler:

  • Tasks that should be done once the device is connect to a power supply

  • Tasks that require network access or a Wi-Fi connection.

  • Task that are not critical or user facing

  • Tasks that should be running on a regular basis as batch where the timing is not critical

1.4. Create a Job

A unit of work is encapsulated by a JobInfo object. This object specifies the scheduling criteria. The job scheduler allows to consider the state of the device, e.g., if it is idle or if network is available at the moment. Use the JobInfo.Builder class to configure how the scheduled task should run. You can schedule the task to run under specific conditions, such as:

  • Device is charging

  • Device is connected to an unmetered network

  • Device is idle

  • Start before a certain deadline

  • Start within a predefined time window, e.g., within the next hour

  • Start after a minimal delay, e.g., wait a minimum of 10 minutes

These constraints can be combined. For example, you can schedule a job every 20 minutes, whenever the device is connected to an unmetered network. Deadline is a hard constraint, if that expires the job is always scheduled.

To implement a Job, extend the JobService class and implement the onStartJob and onStopJob. If the job fails for some reason, return true from on the onStopJob to restart the job. The onStartJob is performed in the main thread, if you start asynchronous processing in this method, return true otherwise false.

The new JobService must be registered in the Android manifest with the BIND_JOB_SERVICE permission.

 <service
            android:name=".TestJobService"
            android:label="Word service"
            android:permission="android.permission.BIND_JOB_SERVICE" >

</service>

2. Exercise: Preparation

The following exercise is based on the Android local service exercise.

3. Exercise: Use JobScheduler from a receiver

You learn how to use the Android job scheduler to trigger a service from a broadcast receiver. You also register this receiver for the android.intent.action.BOOT_COMPLETED broadcast which is send after a reboot of the Android system. The registered receiver uses the job scheduler to trigger your custom service on a regular basis.

3.1. Create the receiver

Create the following utility class.

package com.vogella.android.localservice;

import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;

public class Util {

    // schedule the start of the service every 10 - 30 seconds
    public static void scheduleJob(Context context) {
        ComponentName serviceComponent = new ComponentName(context, TestJobService.class);
        JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
        builder.setMinimumLatency(1 * 1000); // wait at least
        builder.setOverrideDeadline(3 * 1000); // maximum delay
        //builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); // require unmetered network
        //builder.setRequiresDeviceIdle(true); // device should be idle
        //builder.setRequiresCharging(false); // we don't care if the device is charging or not
        JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
        jobScheduler.schedule(builder.build());
    }

}

Create the following receiver

package com.vogella.android.localservice;

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

public class MyStartServiceReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Util.scheduleJob(context);
    }
}

Register the receiver in the Android manifest for the BOOT_COMPLETED event.

<receiver android:name="MyStartServiceReceiver" >
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

3.2. Create your job

package com.vogella.android.localservice;

import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.Intent;

/**
 * JobService to be scheduled by the JobScheduler.
 * start another service
 */
public class TestJobService extends JobService {
    private static final String TAG = "SyncService";

    @Override
    public boolean onStartJob(JobParameters params) {
        Intent service = new Intent(getApplicationContext(), LocalWordService.class);
        getApplicationContext().startService(service);
        Util.scheduleJob(getApplicationContext()); // reschedule the job
        return true;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        return true;
    }

}

3.3. Trigger the boot completed event from the command line

~/Android/Sdk/platform-tools$ ./adb root
~/Android/Sdk/platform-tools$ ./adb shell am broadcast -a android.intent.action.BOOT_COMPLETED

3.4. Validate

Trigger the boot completed event from the command line or reboot your device. Start your application. Update the data in the list, the list should grow longer until it reaches 20 entries.

4. Links and Literature

Nothing listed.

If you need more assistance we offer Online Training and Onsite training as well as consulting