Android JobScheduler Example

When working with Android, there will be occasions where you want to run a task at a later point in time or under certain conditions, such as when a device is plugged into a power source or connected to a Wi-Fi network. Google has provided a new component known as the JobScheduler API to handle this very scenario.

Android JobScheduler API is a better choice for scheduling background jobs for your application.It improves the battery life by performing similar jobs as batches in the background.It is the better alternative for AlarmManager and syncAdapters.

In this tutorial, you will learn how to use the JobScheduler API  for running a task in background. The JobScheduler API allows developers to create jobs that execute in the background when certain conditions are met.

Get GITHUB code from here.

  • Create a new Android project with a minimum required API of 21, because the JobScheduler API works only on API level 21 and above.
  • Firstly create a new Java class that extends JobService class. To keep things simple, let’s name it JobSchedulerService .
  • Now you must override two methods onStartJob(JobParameters params) and onStopJob(JobParameters params).
public class JobSchedulerService extends JobService {

    @Override
    public boolean onStartJob(JobParameters jobParameters) {
        
        return false;
    }

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

 

onStartJob(JobParameters params) :

  • This method is called by the system when all the job parameters are met and the time for job execution arrived.
  • You can place your job in this method.
  • you must return a boolean from this method.
  • If the return value is false, the system assumes that whatever task has run did not take long and is done by the time the method returns(false).
  • Always keep in mind that the  job service runs on your application’s main thread. This means that you have to use another thread, a handler, or an asynchronous task to run longer tasks to not block the main thread.
  • If you place your job in separate thread then you have to return true from the onStartJob() method.
  • If the return value is true, then the system assumes that your job is still running in a separate thread and the burden falls on you, the developer, to tell the system when the given task is complete by calling jobFinished(JobParameters params, boolean needsRescheduled).
  • For the jobFinished() you have to pass two parameters:
  1. Job parameters.
  2. Boolean(return true if you want to re-scheduled the same job again otherwise false).

 

onStopJob(JobParameters params) :

  • System called this method if your background job is cancelled before being finished.This happens if any of your job parameters are no longer available.For example wifi cuts off while downloading a file.
  • You can clear the unfinished job resources from this method.
  • You have to return true from this method if you want to re-scheduled the same job again otherwise return false.

 

Here we will use  AsynTask to run our job in  JobSchedulerService class.

private static class JobTask extends AsyncTask<JobParameters, Void, JobParameters> {
    private final JobService jobService;

    public JobTask(JobService jobService) {
        this.jobService = jobService;
    }

    @Override
    protected JobParameters doInBackground(JobParameters... params) {

//Place your code here
        for(int i=1;i<=10;i++)
        {
            Log.e("number","num"+i);
        }

        return params[0];
    }

    @Override
    protected void onPostExecute(JobParameters jobParameters) {
        jobService.jobFinished(jobParameters, false);
    }
}

In the AsyncTask, implement the doInBackground(JobParameters… params)  method  and the onPostExecute(JobParameters jobParameters).Inside the doInBackground method, to keep things simple we will print the numbers from 1 to 10 though this is where you can put the logic of your own task which you want to execute.

In onPostExecute method ,when the task is done, you need to call jobFinished(JobParameters params, boolean needsRescheduled) to let the system know that you’re done with that task and now it can begin queuing up the next operation. If you don’t do this, your jobs will only run once and your application will not be allowed to perform additional jobs.

With the AsyncTask created, you can go ahead and start implementing the onStartJob(JobParameters params) and onStopJob(JobParameters params) methods to control your tasks. You’ll notice that in the following code snippet, the onStartJob(JobParameters params) method returns true. This is because you’re going to use an AsyncTask  to control your operation, which means that it could take longer to finish than the onStartJob(JobParameters params) method. By returning true, you’re letting the application know that you will manually call the jobFinished(JobParameters params, boolean needsRescheduled) method.

@Override
public boolean onStartJob(JobParameters jobParameters) {
    Toast.makeText(getApplicationContext(), "Job started ", Toast.LENGTH_LONG).show();
    new JobTask(this).execute(jobParameters);

    return true;
}

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

Once you’re done with the Java portion of the JobSchedulerService class, you need to go into AndroidManifest.xml and add a node for the service so that your application has permission to bind and use this class as a JobService.

<service android:name=".JobSchedulerService"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:exported="true"/>

With JobSchedulerService class finished, we can start looking at how your application will interact with the JobScheduler API. The first thing you will need to do is create a JobScheduler object, called jobScheduler in the sample code, and initialize it by getting an instance of the system service JOB_SCHEDULER_SERVICE. In the sample application, this is done in the MainActivity class.

final JobScheduler jobScheduler =
        (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);

When you want to create your scheduled task, you can use the JobInfo.Builder to construct a JobInfo object that gets passed to your service. To create a JobInfo object, JobInfo.Builder accepts two parameters. The first is the identifier of the job that you will run and the second is the component name of the service that you will use with the JobScheduler API.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    jobInfo = new JobInfo.Builder(JOB_ID, new ComponentName(this, JobSchedulerService.class))
            .setPeriodic(15*60*1000,7*60*1000)
            .build();

} else
{
    jobInfo = new JobInfo.Builder(JOB_ID, new ComponentName(this, JobSchedulerService.class))
            .setPeriodic(60*1000)
            .build();
}

This builder allows you to set many different options for controlling when your job will execute. The following code snippet shows how you could set your task to run periodically every one minute.It works well in Lollipop & Marshmallow only.

jobInfo.setPeriodic(60*1000);
  • setPeriodic(long intervalMillis) : Specify that this job should recur with the provided interval, not more than once per period. You have no control over when within this interval this job will be executed,only the guarantee that it will be executed at most once within this interval.

For Nougat and above we have to write the below code:

jobInfo.setPeriodic(15*60*1000,7*60*1000)
  • setPeriodic(long intervalMillis,long flexMillis) : This method accepts 2 parameters :
    intervalMs The job should run at most once every intervalMs. The minimum value is 15min.
    flexMs How close to the end of the period the job should run. The minimum value is 5min.

So our task will run every 15 minutes. And since our flex parameter is set to 7 minutes the library will determine the best moment between 8th and 15th minute to execute the JobSchedulerService.

Other methods include:

  • setMinimumLatency(long minLatencyMillis) : This makes your job not launch until the stated number of milliseconds have passed. This is incompatible with setPeriodic(long time) and will cause an exception to be thrown if they are both used.
  • setOverrideDeadline(long maxExecutionDelayMillis) : This will set a deadline for your job. Even if other requirements are not met, your task will start approximately when the stated time has passed. Like setMinimumLatency(long time), this function is mutually exclusive with setPeriodic(long time) and will cause an exception to be thrown if they are both used.
  • setPersisted(boolean isPersisted) : This function tells the system whether your task should continue to exist after the device has been rebooted.
  • setRequiredNetworkType(int networkType) : This function will tell your job that it can only start if the device is on a specific kind of network. The default is JobInfo.NETWORK_TYPE_NONE, meaning that the task can run whether there is network connectivity or not. The other two available types are JobInfo.NETWORK_TYPE_ANY, which requires some type of network connection available for the job to run, and JobInfo.NETWORK_TYPE_UNMETERED, which requires that the device be on a non-cellular network.
  • setRequiresCharging(boolean requiresCharging) : Using this function will tell your application that the job should not start until the device has started charging.
  • setRequiresDeviceIdle(boolean requiresDeviceIdle) : This tells your job to not start unless the user is not using their device and they have not used it for some time.

Once the preferred conditions are stated, you can build the JobInfo object and send it to your JobScheduler object as shown below.

jobScheduler.schedule(jobInfo);

We can also check whether the schedule fails or not by writting below code:

if( jobScheduler.schedule( builder.build() ) <= 0 ) {
    //If something goes wrong
        }

You’ll notice that the schedule operation returns an integer. If schedule fails, it will return a value of zero or less, corresponding to an error code. Otherwise it will return the job identifier that we defined in the JobInfo.Builder.

If your application requires that you stop a specific or all jobs, you can do so by calling cancel(int jobId) or cancelAll() on the JobScheduler object.

jobScheduler.cancel(JOB_ID);
jobScheduler.cancelAll();

You should now be able to use the JobScheduler API with your own applications to batch jobs and run background operations.

1 thought on “Android JobScheduler Example”

Leave a Reply