Android Job Scheduler – Scheduling of Tasks


JobScheduler was introduced in Lollipop and is pretty cool because it performs work based on conditions, not on time. Job scheduling APIs let developers schedule work to be done when certain conditions are met instead of at a specified time. So rather than scheduling a download for 1 am and needing to worry about whether the device is charging or on an expensive data connection, we can just use the JobScheduler and tell it not to start our job until the device is charging and on Wi-Fi.

Our goal with JobScheduler was to find a way for the system to shoulder part of the burden of creating performant apps. As a developer, we do our part to create an app that doesn’t freeze, but that doesn’t always translate to the battery life of the device being healthy. So, by introducing JobScheduler at the system level, we can focus on batching similar work requests together, which results in a noticeable improvement for both battery and memory.

Scheduling Options

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 a 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.

Luckily, using the JobScheduler is pretty straightforward. There are only three things we need to do:

  1. Create a JobService to handle your job
  2. Add that JobService to the manifest
  3. Schedule your job using a JobInfo object to define your conditions

Creating a JobService

job service is a specialized Service (i.e. extended Service) with a couple of methods to help us handle our job. To create a job service, start by extending the JobService class and overriding ‘onStartJob’ and ‘nonstop job’. OnStartJob is called by the Android system when it starts your job. However, on top job is only called if the job was canceled before being finished (e.g. we require the device to be charging, and it gets unplugged).

Also, when your job is finished (has been completed or canceled) you’re responsible for calling the ‘job finished’ method. The ‘job finished’ method tells Android that your job is done and lets it release the wake lock for your app. If you don’t call the ‘job finished’ method your app could be responsible for draining your user’s battery!

Here’s an example of a simple Job Service that does 10 seconds of ‘work’ on a new Thread:

public class MyJobService extends JobService { private static final String TAG = MyJobService.class.getSimpleName(); boolean isWorking = false; boolean jobCancelled = false; @Override public boolean onStartJob(JobParameters jobParameters) { Log.d(TAG, “Job started!”); isWorking = true; startWorkOnNewThread(jobParameters); // Services do NOT run on a separate thread return isWorking; }private void startWorkOnNewThread(final JobParameters jobParameters) { new Thread(new Runnable() { public void run() { doWork(jobParameters); } }).start(); }

private void doWork(JobParameters jobParameters) { for (int i = 0; i < 1000; i++) { if (jobCancelled) return; try {

Thread.sleep(10); } catch (Exception e) { } }

Log.d(TAG, “Job finished!”); isWorking = false; boolean needsReschedule = false; jobFinished(jobParameters, needsReschedule); }

// Called if the job was cancelled before being finished @Override public boolean onStopJob(JobParameters jobParameters) { Log.d(TAG, “Job cancelled before being completed.”); jobCancelled = true; boolean needsReschedule = isWorking; jobFinished(jobParameters, needsReschedule); return needsReschedule; } }

Adding the JobService to the Manifest

Since a JobService IS a Service, you’ll need to declare it in your manifest. The only catch is that since it’s a JobService you also need to include the BIND_JOB_SERVICE permission.


Scheduling the Job

When it’s time to schedule your job you’ll need to start with a JobInfo object. A JobInfo object contains all your job details and is used by the JobScheduler to schedule your job. To create a JobInfo you’ll need to use a JobInfo.Builder and supply it with a ‘jobId’ (integer of your choosing) and the ComponentName of your job service. Then you’ll add any conditions you need (e.g. set periodic), and build the JobInfo object:

ComponentName componentName = new ComponentName(this, MyJobService.class); JobInfo jobInfo = new JobInfo.Builder(12, componentName) .setRequiresCharging(true) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .build();

Once you’ve got your JobInfo, all that’s left is scheduling your job. Just grab a reference to the JobScheduler and call the ‘schedule’ method!

JobScheduler jobScheduler = (JobScheduler)getSystemService(JOB_SCHEDULER_SERVICE); int resultCode = jobScheduler.schedule(jobInfo); if (resultCode == JobScheduler.RESULT_SUCCESS) { Log.d(TAG, “Job scheduled!”); } else { Log.d(TAG, “Job not scheduled”); }

A good way to test that this works would be to run the app on a connected device and then turn the WiFi off to see if the job gets canceled. Then turn the WiFi back on, and after a couple of minutes, you should be able to see your job restarted. So the next time you’re planning a download in the background, think about giving your users a little more battery life by using the JobScheduler!