Job Scheduler -An Overview
Do you have the above question in your mind! then you would have probably thinking about the way to create background tasks in your android application or modify your existing one. Over a period of time Google has introduced so many APIs for scheduling background Tasks. Why google has to do that? simply they could tell the developers to use any old APIs which are already well coded and optimized. The reason behind this is we all know background services are the efficient consumers of device battery. As everyday apps are growing, there are lot of things that can happen which can significantly drain the device battery effectively. This will not only leave with the battery draining but also could give very bad user experience. To avoid this Google has imposed some serious steps by putting some restrictions on background works.
We as Android developers, it is our responsibility to choose the right background services and schedulers for our application which gives the best end user experience and minimal battery usage. It is our time to wake up. So let’s move onto our discussion.
There are so many ways we can schedule the background tasks. There are lot of simple and best threads available where you can read about it. We are having,
- Handlers
- Alarm Manager
- GCM Network Manager
- Firebase job dispatcher
- Sync adapter etc.
for scheduling background tasks. But where in Job scheduler fits?
What is Job Scheduler?
Job scheduler is the Android Framework API for scheduling Background tasks or services.
It was introduced by Google in API 21. For the APIs below than 21, the alternatives are GCM Network Manager, Firebase Job Dispatcher and evernote/android-job etc.
Internally GCM Network Manager and Firebase Job Dispatcher uses Job scheduler as their service API. But from API 21 onwards Google has given Job scheduler as the platform implemented API . This API gives the abstract layer of Job scheduling service. So we don’t want to care much about how it is scheduling the service.
The main thing here is It is working based on robust conditions like network availability, device charging state and so on. As a developer we have to set these criteria and rest of the things will be taken care by the API.
Since this is platform implemented API it will be allowed to collect information about jobs that need to run across all apps. This will be helpful in batching similar jobs, so that jobs can stay same during sleep(Doze) mode and thus helps in preserving battery usage.
Where it fits?
The following are the considerable or Must have reasons to use Job Scheduler.
- If we are using API level 21 or above
- Time based task scheduling is not our priority
- Targeting devices that doesn’t have Google Play Services. Again API level ≥ 21.
- Requiring job execution conditions such as device charging, network availability and timing.
- Considering Android platform implemented API rather than third party APIs.
- From Oreo API Level 26, it is the recommended alternative for Implicit broadcast receivers.
We should note here that this adheres to the Doze and App standby Restrictions.
How to use it?
The main things to be considered when using Job scheduler are
1. Create JobService
JobService is the class that extends Service class used by Job Scheduler. This will be triggered by the System when the criteria given by the developer met. This will take the asynchronous requests given by the system.
So first we need to create our Job Logic using JobService. Android System will use this JobService to perform the Tasks.
There are two methods we need to consider here and it is our responsibility to override them. These are abstract methods given by the JobService. Leaving this unimplemented will result in an Error.
- onStartJob()
- onStopJob()
public class SimpleService extends JobService {
@Override
public boolean onStartJob(JobParameters jobParameters) {
return true;
}
@Override
public boolean onStopJob(JobParameters jobParameters) {
return false;
}
}
1. onStartJob()
It is the entry point of JobService class. This will be called when the job begins its execution. This runs on Main Thread. So it is our sole responsibility to spawn any worker thread if required.
@Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d(TAG, “Job Started”);
doSomeService(jobParameters);
return true;
}private void doSomeService(final JobParameters parameters) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
Log.d(TAG, "Running " + i);
if (isJobCancelled)
return;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.d(TAG, "Job Finished");
jobFinished(parameters, false);
}
}).start();
}
If we return false from this method, it indicates that the job we are performing is simple and the job is already finished. This means System will take responsibility of the call completion. This has to be used when we are doing any simple operations like clear cache. Here System’s wakelock will be released and onStopJob() will not be called.
If we return true from this method, it indicates that the job we are performing is a long one and the system will not complete the task on behalf of us or until the criteria met are lost i.e., Criteria that are no longer satisfied. e.g., when criteria requires device charging but the charger disconnected while executing the task.
So here it is the developers responsibility to declare to System that the job was completed using jobFinished(JobParameters, boolean) method. Here System holds a wakelock on behalf of our app until the job scheduled was completed.
Since this is performing the task in main thread it is a good practise to use asynctasks/rx for long running operations. Once the job gets completed we must call jobFinished() method.
jobFinished(JobParameters, boolean)
On Calling this method the System will release the wake lock it holds for the job and calls onStopJob() method.
This takes two parameters. First one, JobParameters we will check later. Second One, boolean wantsReschedule flag indicates that the rescheduling of the job is necessary. It true the job will be rescheduled else it will not. Setting this true will adjust the Job’s back-off policy. It can initially be set using setBackoffCriteria() in the JobInfo Object. The jobs initial requirements will be preserved even we set back-off policy here.
2. onStopJob()
This method will be called either when we manually call jobFinished() method or by system when the job ends up prematurely by losing job execution criteria.
Either way it is the developers responsibility to finish the job and clear the resources when this method is getting invoked. Ignoring this will result in app misbehaviour.
If we return true from this method will allow us to reschedule the job based on the retry criteria provided at job creation-time. System will release the wake lock here.
@Override
public boolean onStopJob(JobParameters jobParameters) {
Log.d(TAG,"Job Cancelled");
isJobCancelled = true;
return false;
}
2. Define Job Parameters
Job parameters define the Job conditions based on the JobInfo Object.
JobInfo object contained the data need to be passed to schedule the job for the calling application. This can be constructed using JobInfo.Builder object.
JobInfo.Builder(int jobId, ComponentName jobService)
Here it is necessary to give a JobId and the ComponentName. ComponentName is nothing but the JobService class we defined. System will identify the Jobservice class using this ComponentName and JobID where JobID is the unique Number. After defining this we need to define the Job parameters or conditions. We must specify at-least one sort of constraint in the Job Parameters. This can be done by applying condition methods on JobInfo.Builder object.
Some of the conditions are
ComponentName name = new ComponentName(this, SimpleService.class);
JobInfo info = new JobInfo.Builder(123, name)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setRequiresCharging(true)
.setPersisted(true)
.setPeriodic(5 * 1000).build();
setRequiredNetworkType will set the conditions for Metered or Unmetered network connections or Any. Metered connection implies cellular network (from API 28 It is deprecated) and Unmetered implies Wifi Network.
setPersisted will set the job to exist even after the Device reboot. For this we need to set the appropriate permission in AndroidManifest.xml.
setPeriodic will set the time delay after which the job has to start.
Finally we need to build JobInfo.Builder object using build() method. Once all set it is time to schedule the job.
2. Schedule the Job
To schedule this first we need to create Job Scheduler object. Since this is built on System level we can access it through get getSystemService() method.
JobScheduler scheduler = (JobScheduler)getSystemService(JOB_SCHEDULER_SERVICE);
int response = scheduler.schedule(info);
Voila! We have created a Job using Job scheduler. Additionally if we want to cancel the Job we can cancel it using
scheduler.cancel(123);
Once we created this, System will automatically run your job when the particular criteria are met.
Job Scheduler Flow
Look at the image given below. It can give us the rough idea about how Job scheduler works.
Conclusion
There are several APIs that your app can use to schedule background work. But if you want to use the native library then JobScheduler
is for you.
The JobScheduler
API allows you to specify robust conditions for executing tasks, along with centralized task scheduling across the device for optimal system health.
JobScheduler
also offers highly scalable functionality: it is suitable for small tasks like clearing a cache, and for large ones such as syncing a database to the cloud.
While i am writing this post Google has already introduced one more API named WorkManager which uses all the functionality of Firebase Job Scheduler, AlarmManager + Broadcasr receiver and Job Scheduler. It supports from API level 14+ and even provides Job-scheduler like capabilities. Based on the condition and features of the device it chooses the best scheduler for scheduling the job. It is the best alternative for the third party library evernote/android-job.