In the modern application development, it is very common for our application to perform tasks asynchronously and scope of them are outside the application’s life-cycle like downloading some data or updating network resources. In some situations we also have to do some work but it is not required to do it right now. To schedule background work, Android introduced several APIs which we can use wisely in our applications.
Selecting a proper scheduler can improve application performance and battery life of the device.
There are several approaches to schedule a task:
Alarm Manager. AlarmManager provides access to system-level alarm services. This give a way to perform any operations outside the lifetime of your application. So you can trigger events or actions even when your application is not running. AlarmManager can startup a service in future. It is used to trigger a PendingIntent when alarm goes off.
Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted.
We should only use AlarmManager API for tasks that must execute at a specific time. This does not provide more robust execution conditions like device is idle, network is available or charging detect.
Use Case: Let’s say we want to perform a task after 1 hour or every 1 hour. In this case AlarmManager works perfectly for us. But this API is not suitable in a situations like perform the above task only when network is available or when device is not charging.
Pros
Cons
Job Scheduler. This is the chief among all the mentioned scheduling options and perform the background work very efficiently. JobScheduler API which was introduced in Android 5.0(API level 21).
This API allows to batch jobs when the device has more resources available or when the right conditions are met. All of the conditions can be defined when you’re creating a job. When the criteria declared are met, the system will execute this job on your application’s JobService
. JobScheduler
also defers the execution as necessary to comply with Doze mode and App Standby restrictions.
Batching job execution in this fashion allows the device to enter and stay in sleep states longer, preserving battery life. In general this API can be used to schedule everything that is not time critical for the user.
Pros
Cons
GCM Network Manager. GCM (Google Cloud Messaging) Network Manager has all the schedule features from JobScheduler
. GCM Network Manager is also meant for performing repeated or one-off, non-imminent work while keeping battery life in mind.
It is used to support backward compatibility and can also use below Android 5.0 (API level 21). From API level 23 or higher, GCM Network Manager uses the framework’s JobScheduler
. GCM Network Manager uses the scheduling engine inside Google Play services so this class will only work if the Google Play services is installed on the device.
Google has strongly recommended for GCM users to upgrade to FCM and instead use Firebase Job Dispatcher for scheduling any tasks.
Pros
Cons
Firebase Job Dispatcher. The Firebase JobDispatcher is also a library for scheduling background jobs. It is also used to support backward compatibility (below API level 21) and works on all recent versions of Android (API level 9+).
This library will also works when running device do not have Google play services installed and wants to schedule a job in the application. In this condition this library internally uses AlarmManager. If Google Play service is available on the device then it uses the scheduling engine inside Google Play services.
Sync Adapter. Sync adapters are designed specifically for syncing data between a device and the cloud. It should be only use for this type of task. Syncs could be triggered from data changes in either the cloud or device, or by elapsed time and time of day. The Android system will try to batch outgoing syncs to save battery life and transfers that are unable to run will queue up for transfer at some later time. The system will attempt syncs only when the device is connected to a network.
Wherever possible, it is advised via Google to use JobScheduler, Firebase JobDispatcher, or GCM Network Manager.
In Android N (API level 24), the SyncManager sits on top of the JobScheduler. You should only use the SyncAdapter class if you require the additional functionality that it provides.
Android-Job. A utility library for Android to run jobs delayed in the background. Depending on the Android version either the JobScheduler, GcmNetworkManager or AlarmManager is getting used.
Smart Scheduler Android. A utility library for Android to schedule one-time or periodic jobs while your app is running.
Setting up and using Android-Job
Include android-job dependency in your app module’s build.gradle file and sync project.
dependencies { ... compile 'com.evernote:android-job:1.2.0' }
Implementing Android-Job is super easy.
The API includes below classes/interfaces.
Job
. Your jobs need to extend this class and override onRunJob
method. The heavy lifting is done here. You must return a Result
from this method so that the system knows whether to attempt to run your job at a later time.JobRequest
. You can schedule a Job
by creating a JobRequest
using its builder constructor and passing your Job tag.JobCreator
. JobCreator
acts like a factory to provide a Job
based on a job tag. Your concrete JobCreator
class must implement the JobCreator
interface and override the create()
method.JobManager
. The JobManager
class serves as the entry point. Before using this class you must initialize this as singleton. JobManager
takes a Context
. After creating the instance, you have to add your JobCreator
to JobManager
.Here we will develop a simple app to show notification to the user periodically.
Let’s create our DoWalkJob
class in the first step.
class DoWalkJob extends Job { static final String TAG = "job_walk_tag"; @NonNull @Override protected Result onRunJob(Params params) { PendingIntent pi = PendingIntent.getActivity(getContext(), 0, new Intent(getContext(), MainActivity.class), 0); Notification notification = new NotificationCompat.Builder(getContext()) .setContentTitle("Do relax") .setContentText("Take a walk.") .setAutoCancel(true) .setContentIntent(pi) .setSmallIcon(R.mipmap.ic_launcher) .setShowWhen(true) .setColor(Color.RED) .setLocalOnly(true) .build(); NotificationManagerCompat.from(getContext()) .notify(new Random().nextInt(), notification); return Result.SUCCESS; } static void schedulePeriodic() { new JobRequest.Builder(DoWalkJob.TAG) .setPeriodic(TimeUnit.MINUTES.toMillis(25), TimeUnit.MINUTES.toMillis(20)) .setUpdateCurrent(true) .build() .schedule(); } }
In the onRunJob
method we are simply showing a notification and we are returning Result.SUCCESS
every time the job runs.
Also we have a static schedulePeriodic
method which builds the JobRequest
through its Builder
and schedules the job by calling schedule()
. We are passing DoWalkJob.TAG in the Builder constructor which tells our JobCreator to return a
DoWalkJob`` instance.
JobRequest.Builder
has many methods. Here we are calling setPeriodic
to tell the system that this is a periodic job which runs every 25 minutes. Also we have passed 20 minutes as the 2nd parameter which is actually the flex time. This helps the system to batch our job with any other jobs with similar time interval.
setUpdateCurrent(true)
will update the current job instead of creating a new job.
Next let’s create our MyCreator
class which implements JobCreator
interface.
class MyCreator implements JobCreator { @Override public Job create(String tag) { switch (tag) { case DoWalkJob.TAG: return new DoWalkJob(); default: return null; } } }
As you can see, in the create()
method we have a switch construct which maps a tag with a specific job.
In the next step we will create our MyApplication
class which extends Application
class. In the MyApplication
class we will create the JobManager
instance by passing our application context and add our MyCreator
to the JobManager
.
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); JobManager.create(this).addJobCreator(new MyCreator()); } }
In the final step we will call the schedulePeriodic
method of our DoWalkJob
class in the onCreate
method of MainActivity
to schedule our job when our application starts.
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DoWalkJob.schedulePeriodic(); } }