Scheduling Work With WorkManager In Android

WorkManager is a part of architecture components in Jetpack. This allows us to schedule a task asynchronously and specify the conditions in which they should run. We can create tasks and hand it off to WorkManager to run immediately or periodically.

WorkManager has the ability to choose an appropriate way to perform the scheduled task. Choosing the appropriate way means it can decide whether a task should be performed on the thread of our application’s process or using AlarmManager, JobScheduler, Firebase or JobDispatcher. Yes, this is the great feature of WorkManager. If our application is not running at the API level of the device, the included dependencies are the factor to decide how jobs should be scheduled.

Adding WorkManager in Project

To add WorkManager in a project, specify the below dependency in module level build.gradle file.

  1. dependencies {  
  2. implementation "android.arch.work:work-runtime:1.0.0-beta02"  
  3. }  

This API is in beta so it may have a bug while executing or scheduling the tasks. WorkManager uses different classes to schedule a job, we need to use a subclass of one of them.

Worker

Worker is an abstract class that extends another abstract class ListenableWorker. ListenableWorker class can perform work asynchronously in WorkManager.

Worker class can perform work synchronously on a background thread provided by WorkManager. When we extend the Worker class, we need to override doWork() method in the class. System instantiates Worker class at runtime and doWork() method is called on the specified background thread.

This method is for synchronous processing of the work, if you want asynchronous processing, ListenableWorker is recommended. A Worker is given a maximum of ten minutes to finish its execution and return a ListenableWorker.Result. After this time has expired, the Worker will be signaled to stop.

WorkRequest

WorkRequest is an abstract class that is used to specify necessary parameters for work that should be queued in WorkManager. We can specify the Worker class where we have written the code to perform the work, the time interval to do periodic tasks, certain conditions or constraints which are the required to perform the task.

WorkRequest.Builder

This is a helper class for creating WorkRequest object. We can use OneTimeWorkRequest.Builder or PeriodicWorkRequest.Builder to perform one-time work or periodic work.

Scheduling One Time Work

The Rubik's Cube is the most popular puzzle. Learn the easiest solution here.

  1. OneTimeWorkRequest compressionWork =  
  2.        new OneTimeWorkRequest.Builder(MyWorker.class)  
  3.                .build();  
  4. WorkManager.getInstance().enqueue(compressionWork);  
Scheduling Periodic Task

To perform periodic tasks like syncing data, you can use PeriodicWorkRequest.Builder and PeriodicWorkRequest object for scheduling the task. You can specify time and units in PeriodicWorkRequest.Builder(), but you cannot have the interval less than 15 minutes. It would not show any error but your task will not be performed in case of interval less than 15 minutes.

  1. PeriodicWorkRequest.Builder builder = new PeriodicWorkRequest.Builder(MyWorker.class15, TimeUnit.MINUTES);  
  2. builder.setConstraints(Constraints.NONE);  
  3. PeriodicWorkRequest workRequest = builder.build();  
  4. WorkManager.getInstance().enqueue(workRequest);  
Cancelling Periodic Work

You can cancel a scheduled task by using cancelWorkById(UUID workId) method of WorkManager. You can get Id of scheduled work by WorkRequest object.

  1. UUID workId = workRequest.getId();  
  2.   
  3. WorkManager.getInstance().cancelWorkById(workId);  
Example

I have created a basic demo application to schedule a one-time task and periodic task. The demo contains a worker class called MyWorker and an Activity to schedule them.

MyWorker class
  1. public class MyWorker extends Worker {  
  2.    public final String TAG = MyWorker.class.getSimpleName();  
  3.   
  4.    public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {  
  5.        super(context, workerParams);  
  6.    }  
  7.   
  8.    @NonNull  
  9.    @Override  
  10.    public Result doWork() {  
  11.        Log.v(TAG, "Work is in progress");  
  12.   
  13.        try {  
  14.            Thread.sleep(1000);  
  15.        } catch (InterruptedException e) {  
  16.            e.printStackTrace();  
  17.        }  
  18.        Log.v(TAG, "Work finished");  
  19.        return Worker.Result.success();  
  20.    }  
  21. }  

WorkManagerDemoActivity class

  1. public class WorkManagerDemoActivity extends AppCompatActivity {  
  2.   
  3.    private boolean mIsPeriodicWorkScheduled = false;  
  4.    private Button mPeriodicWorkButton;  
  5.   
  6.    @Override  
  7.    protected void onCreate(Bundle savedInstanceState) {  
  8.        super.onCreate(savedInstanceState);  
  9.        setContentView(R.layout.activity_work_manager_demo);  
  10.   
  11.        mPeriodicWorkButton = findViewById(R.id.button_schedule_periodic_work);  
  12.        // One time work  
  13.        findViewById(R.id.button_schedule_one_time).setOnClickListener(new View.OnClickListener() {  
  14.            @Override  
  15.            public void onClick(View v) {  
  16.                OneTimeWorkRequest compressionWork =  
  17.                        new OneTimeWorkRequest.Builder(MyWorker.class)  
  18.                                .build();  
  19.                WorkManager.getInstance().enqueue(compressionWork);  
  20.   
  21.            }  
  22.        });  
  23.   
  24.        // Periodic work  
  25.        mPeriodicWorkButton.setOnClickListener(new View.OnClickListener() {  
  26.            @Override  
  27.            public void onClick(View v) {  
  28.   
  29.                PeriodicWorkRequest.Builder builder = new PeriodicWorkRequest.Builder(MyWorker.class15, TimeUnit.MINUTES);  
  30.                builder.setConstraints(Constraints.NONE);  
  31.                PeriodicWorkRequest workRequest = builder.build();  
  32.   
  33.                if (mIsPeriodicWorkScheduled) {  
  34.   
  35.                    UUID workId = workRequest.getId();  
  36.   
  37.                    WorkManager.getInstance().cancelWorkById(workId);  
  38.   
  39.                    mPeriodicWorkButton.setText("Schedule Periodic Work");  
  40.   
  41.                    mIsPeriodicWorkScheduled = false;  
  42.   
  43.                } else {  
  44.   
  45.                    WorkManager.getInstance().enqueue(workRequest);  
  46.   
  47.                    mIsPeriodicWorkScheduled = true;  
  48.   
  49.                    mPeriodicWorkButton.setText("Cancel Periodic Work");  
  50.                }  
  51.            }  
  52.        });  
  53.    }  
  54. }  

Layout of Activity

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.    xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.    xmlns:tools="http://schemas.android.com/tools"  
  5.    android:layout_width="match_parent"  
  6.    android:layout_height="match_parent"  
  7.    android:gravity="center_horizontal"  
  8.    android:orientation="vertical"  
  9.    android:padding="20dp"  
  10.    tools:context="com.example.atiwari.beprepare.work_manager.WorkManagerDemoActivity">  
  11.   
  12.    <Button  
  13.        android:id="@+id/button_schedule_one_time"  
  14.        android:layout_width="wrap_content"  
  15.        android:layout_height="wrap_content"  
  16.        android:text="Schedule One Time Work" />  
  17.   
  18.    <Button  
  19.        android:id="@+id/button_schedule_periodic_work"  
  20.        android:layout_width="wrap_content"  
  21.        android:layout_height="wrap_content"  
  22.        android:text="Schedule Periodic Work" />  
  23. </LinearLayout>  

If you have any issue while implementing this, please write me in the comment section.

Thank you.