- Scheduling of tasks with the Android JobScheduler — Tutorial
- 1. Scheduling tasks
- 1.1. Options for scheduling
- 1.2. The job scheduler API
- 1.3. Advantages of the job scheduler API
- 1.4. Create a Job
- Android JobScheduler — Schedule your jobs like a master!
- Android Job Scheduler
- Overview
- Requirements
- Using the Android Job Scheduler
- Implement a JobService
- Creating a JobInfo to schedule a job
- Passing parameters to a job via the JobInfo
- Scheduling a job
- Cancelling a job
- Summary
Scheduling of tasks with the Android JobScheduler — Tutorial
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
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.
Источник
Android JobScheduler — Schedule your jobs like a master!
May 3, 2020 · 7 min read
Before job schedulers, whenever I encountered a use case where I wanted to do some background processing, I had to make decisions about which android primitive to use. I had to weigh in the pros and cons of each and then proceed with it.
- AsyncTasks
- Combination of handlerThreads and services.
3. Java 5 executor services.
4. Combination of AlarmManager with broadcast receivers and intent services and many more.
One thing was common in all these appr o aches, as a developer, I had to handle lots of things apart from the business logic, such as when do we trigger this service? How to make sure the services fire even if the app is killed, how to make sure that alarms are fired at regular intervals? If work is aborted, then how will we retry? When to acquire wake locks and when to release them and many more things. I had to write lots of code for doing all these things.
After the introduction of JobScheduler, we as developers we have to prepare a contract of how we need the job to get scheduled and what are the conditions in which jobs will execute and hand it over to the Android framework, and we can focus on the work that needs to be done. Android will execute your job at correct times. Android system has a service running called “JobSchedulerService” which executes your requests. We will learn more about the internals of this service in upcoming posts.
If we want to know job schedulers thoroughly, we need to understand the various classes present the API and their uses. We will deal with 2 basic classes that will help us create jobs right after this article.
JobInfo — The class is an abstraction that hides the task that needs to be done and the conditions under which the tasks will get executed. As I explained earlier, this is our contract with the JobScheduler. We do not have to build this class directly, we have accessor methods in this class to examine the contract. We have a builder available to build instances of JobInfo. We submit job info to the job schedulers. We can post multiple work items to a single jobInfo. We will learn how to do it. Usually, related work should be kept under the same job info.
The analogy should be JobInfo is your offlice job, and each work item object ie JobWorkItem is work which you get. One JobInfo can use used to enqueue multiple JobWorkItem
JobInfo.Builder — Create your contract with the JobScheduler service using this builder. Now let’s understand why the APIs look like what they are.
Suppose you are exposing a service to other applications so that you can process requests coming from them. You will need to establish a contract for the kinds of requests you receive. The contract must specify,
- The request which needs to get processed.
2. Must specify a unique identifier for each request so that requests can be accessed at any point in time.
3. Any special requests or flags which give additional information about how the requests need to be processed.
This the same with JobScheduler. JobInfo.Builder exposes a constructor that accepts jobID and the piece of work that needs to get executed. A bare minimum to create a contract!
Through this class, we can specify criteria for our jobs, whether we need a network or not, if yes, then what type of network, the job is periodic or not, its battery requirements, delay tolerance and many more.
There are lots of constraints that we can specify and certain rules which are followed by framework while evaluating these constraints. Will will discuss that in another post.
After android Q you can just create job info without any constraint and the job scheduler happily accepts it. Before Q the app will crash. So the question is how the job will get executed then without any constraints? Majority of contraints have default values. Execution strategy will be determined by the default values of contraints. More details later on. Let’s keep our focus on!
JobService — This is the block of work that we create and provide to the android JobSchedulerService via the JobInfo and whenever the constraints match, JobService’s callbacks are fired.
For each job service we create, we need to add this permission in the android manifest.
We can execute one or more units of related work inside a JobService by enqueuing multiple work items to single JobInfo, for now, we will understand just with JobService.
The API exposes 3 methods,
Once we submit our job info to the job scheduler service using schedule() call, what happens is demonstrated in diagram 1. We will call the job scheduler service as “ System” from now for ease of speaking.
- Once the System determines that the constraints, we provided are satisfied, it calls onStartJob() callback of your job service, this is where we should respond to it and do our job. The system acquires wakelock on your behalf, if we do not have to do anything computation-intensive then we can finish our work and return false from this callback.
Returning false means we say that our job is done, release all the wake-locks and other resources acquired on my behalf, and mark the job as done.
Returning true tells the system that, the job is not done right now, we do not know when it will get finished as it might be running in the background. But once the job is finished, we will let you know. Job completion, in this case, is indicated by the jobFinished() method. Till we call this method, system will hold on to all the resources for us.
2. Whenever the constraints for our jobinfo are no longer satisfied, the system gives a callback to onStopJob() of JobService. Here, we need to make sure that we stop our job entirely or we can save the state so that we can resume when the constraints are satisfied again. Once this method returns, the system will release all the resources. The return values here also convey different meanings.
Returning true means we want to job to reschedule it later when constraints are again met.
Returning false means we want to end this job entirely right now and the job scheduler will not call onStartJob() when the constraint will be satisfied again
These callbacks and methods allow us to bring in save — n — resume strategy in our approach. The best approach would be to divide the whole job into multiple granular units and mark the state of the job as and when work is done so that the next execution can pick up from where we left the last time.
I will explain this with a working example where work is mimicked by a counter task which will count till 100, each count can be considered a granular unit of work. It can be downloading an image or writing/reading a record to/from the server.
Code to schedule the above JobService is
The above job should run when the network is available, when you run the above job it will start printing numbers from 0,1,2,3. When the network is disconnected by turning wifi off it stops the job and prints Job paused. When the network is again turned on, it resumes from 3,4,5. and so on.
If your job is such that you can’t break it into pieces then, finish it on onStopJob() callback by returning true from it. When the next time the constraints will be satisfied, the whole job will be re-run.
If your job does not require any background processing and asynchronous work then, no need to create async tasks or any other multi-threading primitive. Just do your work in onStartJob() itself and return false to indicate that your job is done. This is useful if you just want to send some broadcast or something of that kind.
The job scheduler provides some APIs to query, cancel, and enqueue jobs, which doesn’t require much explanation.
This is how we work with JobScheduler APIs. Next, we will see how we can enqueue multiple work items to a given JobInfo. It is always a good idea to tie related work into a single JobInfo.
Источник
Android Job Scheduler
This guide discusses how to schedule background work using the Android Job Scheduler API, which is available on Android devices running Android 5.0 (API level 21) and higher.
Overview
One of the best ways to keep an Android application responsive to the user is to ensure that complex or long running work is performed in the background. However, it is important that background work will not negatively impact the user’s experience with the device.
For example, a background job might poll a website every three or four minutes to query for changes to a particular dataset. This seems benign, however it would have a disastrous impact on battery life. The application will repeatedly wake up the device, elevate the CPU to a higher power state, power up the radios, make the network requests, and then processing the results. It gets worse because the device will not immediately power down and return to the low-power idle state. Poorly scheduled background work may inadvertently keep the device in a state with unnecessary and excessive power requirements. This seemingly innocent activity (polling a website) will render the device unusable in a relatively short period of time.
Android provides the following APIs to help with performing work in the background but by themselves they are not sufficient for intelligent job scheduling.
- Intent Services – Intent Services are great for performing the work, however they provide no way to schedule work.
- AlarmManager – These APIs only allow work to be scheduled but provide no way to actually perform the work. Also, the AlarmManager only allows time based constraints, which means raise an alarm at a certain time or after a certain period of time has elapsed.
- Broadcast Receivers – An Android app can setup broadcast receivers to perform work in response to system-wide events or Intents. However, broadcast receivers don’t provide any control over when the job should be run. Also changes in the Android operating system will restrict when broadcast receivers will work, or the kinds of work that they can respond to.
There are two key features to efficiently performing background work (sometimes referred to as a background job or a job):
- Intelligently scheduling the work – It is important that when an application is doing work in the background that it does so as a good citizen. Ideally, the application should not demand that a job be run. Instead, the application should specify conditions that must be met for when the job can run, and then schedule that job with the operating system that will perform the work when the conditions are met. This allows Android to run the job to ensure maximum efficiency on the device. For example, network requests may be batched to run all at the same time to make maximum use of overhead involved with networking.
- Encapsulating the work – The code to perform the background work should be encapsulated in a discrete component that can be run independently of the user interface and will be relatively easy to reschedule if the work fails to complete for some reason.
The Android Job Scheduler is a framework built in to the Android operating system that provides a fluent API to simplify scheduling background work. The Android Job Scheduler consists of the following types:
- The Android.App.Job.JobScheduler is a system service that is used to schedule, execute, and if necessary cancel, jobs on behalf of an Android application.
- An Android.App.Job.JobService is an abstract class that must be extended with the logic that will run the job on the main thread of the application. This means that the JobService is responsible for how the work is to be performed asynchronously.
- An Android.App.Job.JobInfo object holds the criteria to guide Android when the job should run.
To schedule work with the Android Job Scheduler, a Xamarin.Android application must encapsulate the code in a class that extends the JobService class. JobService has three lifecycle methods that can be called during the lifetime of the job:
bool OnStartJob(JobParameters parameters) – This method is called by the JobScheduler to perform work, and runs on the main thread of the application. It is the responsibility of the JobService to asynchronously perform the work and return true if there is work remaining, or false if the work is done.
When the JobScheduler calls this method, it will request and retain a wakelock from Android for the duration of the job. When the job is finished, it is the responsibility of the JobService to tell the JobScheduler of this fact by call the JobFinished method (described next).
JobFinished(JobParameters parameters, bool needsReschedule) – This method must be called by the JobService to tell the JobScheduler that the work is done. If JobFinished is not called, the JobScheduler will not remove the wakelock, causing unnecessary battery drain.
bool OnStopJob(JobParameters parameters) – This is called when the job is prematurely stopped by Android. It should return true if the job should be rescheduled based on the retry criteria (discussed below in more detail).
It is possible to specify constraints or triggers that will control when a job can or should run. For example, it is possible to constrain a job so that it will only run when the device is charging or to start a job when a picture is taken.
This guide will discuss in detail how to implement a JobService class and schedule it with the JobScheduler .
Requirements
The Android Job Scheduler requires Android API level 21 (Android 5.0) or higher.
Using the Android Job Scheduler
There are three steps for using the Android JobScheduler API:
- Implement a JobService type to encapsulate the work.
- Use a JobInfo.Builder object to create the JobInfo object that will hold the criteria for the JobScheduler to run the job.
- Schedule the job using JobScheduler.Schedule .
Implement a JobService
All work performed by the Android Job Scheduler library must be done in a type that extends the Android.App.Job.JobService abstract class. Creating a JobService is very similar to creating a Service with the Android framework:
- Extend the JobService class.
- Decorate the subclass with the ServiceAttribute and set the Name parameter to a string that is made up of the package name and the name of the class (see the following example).
- Set the Permission property on the ServiceAttribute to the string android.permission.BIND_JOB_SERVICE .
- Override the OnStartJob method, adding the code to perform the work. Android will invoke this method on the main thread of the application to run the job. Work that will take longer that a few milliseconds should be performed on a thread to avoid blocking the application.
- When the work is done, the JobService must call the JobFinished method. This method is how JobService tells the JobScheduler that work is done. Failure to call JobFinished will result in the JobService putting unnecessary demands on the device, shortening the battery life.
- It is a good idea to also override the OnStopJob method. This method is called by Android when the job is being shut down before it is finished and provides the JobService with an opportunity to properly dispose of any resources. This method should return true if it is necessary to reschedule the job, or false if it is not desirable to re-run the job.
The following code is an example of the simplest JobService for an application, using the TPL to asynchronously perform some work:
Creating a JobInfo to schedule a job
Xamarin.Android applications do not instantiate a JobService directly, instead they will pass a JobInfo object to the JobScheduler . The JobScheduler will instantiate the requested JobService object, scheduling and running the JobService according to the metadata in the JobInfo . A JobInfo object must contain the following information:
- JobId – this is an int value that is used to identify a job to the JobScheduler . Reusing this value will update any existing jobs. The value must be unique for the application.
- JobService – this parameter is a ComponentName that explicitly identifies the type that the JobScheduler should use to run a job.
This extension method demonstrates how to create a JobInfo.Builder with an Android Context , such as an Activity:
A powerful feature of the Android Job Scheduler is the ability to control when a job runs or under what conditions a job may run. The following table describes some of the methods on JobInfo.Builder that allow an app to influence when a job can run:
Method | Description |
---|---|
SetMinimumLatency | Specifies that a delay (in milliseconds) that should be observed before a job is run. |
SetOverridingDeadline | Declares the that the job must run before this time (in milliseconds) has elapsed. |
SetRequiredNetworkType | Specifies the network requirements for a job. |
SetRequiresBatteryNotLow | The job may only run when the device is not displaying a «low battery» warning to the user. |
SetRequiresCharging | The job may only run when the battery is charging. |
SetDeviceIdle | The job will run when the device is busy. |
SetPeriodic | Specifies that the job should be regularly run. |
SetPersisted | The job should perisist across device reboots. |
The SetBackoffCriteria provides some guidance on how long the JobScheduler should wait before trying to run a job again. There are two parts to the backoff criteria: a delay in milliseconds (default value of 30 seconds)and type of back off that should be used (sometimes referred to as the backoff policy or the retry policy). The two policies are encapsulated in the Android.App.Job.BackoffPolicy enum:
- BackoffPolicy.Exponential – An exponential backoff policy will increase the initial backoff value exponentially after each failure. The first time a job fails, the library will wait the initial interval that is specified before rescheduling the job – example 30 seconds. The second time the job fails, the library will wait at least 60 seconds before trying to run the job. After the third failed attempt, the library will wait 120 seconds, and so on. This is the default value.
- BackoffPolicy.Linear – This strategy is a linear backoff that the job should be rescheduled to run at set intervals (until it succeeds). Linear backoff is best suited for work that must be completed as soon as possible or for problems that will quickly resolve themselves.
For more details on create a JobInfo object, please read Google’s documentation for the JobInfo.Builder class.
Passing parameters to a job via the JobInfo
Parameters are passed to a job by creating a PersistableBundle that is passed along with the Job.Builder.SetExtras method:
The PersistableBundle is accessed from the Android.App.Job.JobParameters.Extras property in the OnStartJob method of a JobService :
Scheduling a job
To schedule a job, a Xamarin.Android application will get a reference to the JobScheduler system service and call the JobScheduler.Schedule method with the JobInfo object that was created in the previous step. JobScheduler.Schedule will immediately return with one of two integer values:
- JobScheduler.ResultSuccess – The job has been successfully scheduled.
- JobScheduler.ResultFailure – The job could not be scheduled. This is typically caused by conflicting JobInfo parameters.
This code is an example of scheduling a job and notifying the user of the results of the scheduling attempt:
Cancelling a job
It is possible to cancel all the jobs that have been scheduled, or just a single job using the JobsScheduler.CancelAll() method or the JobScheduler.Cancel(jobId) method:
Summary
This guide discussed how to use the Android Job Scheduler to intelligently perform work in the background. It discussed how to encapsulate the work to be performed as a JobService and how to use the JobScheduler to schedule that work, specifying the criteria with a JobTrigger and how failures should be handled with a RetryStrategy .
Источник