Architecture Components

Scheduling Recurring Task in Android | WorkManager

I have written a complete tutorials series on WorkManager. In this series, we explained about WorkManager, How’s it’s working, and explained how run tasks under specific conditions using WorkManager. In this tutorial, I’m going to explain how to schedule a recurring or repetitive task in Android. In other words, In this article, we learn about cron job in android.

WorkManager?

WorkManager is a task scheduler, it makes easy to specify the asynchronous task. The Work Manager API helps create the task and hand it to the Work Manager to run immediately or at an appropriate time as mentioned.

Types of work supported by WorkManager

WorkManager is support two type work. OneTimeWorkRequest and PeriodicWorkRequest.

1. OneTimeWorkRequest

As per name OneTimeWorkRequest for non-repeating work. Mean if you want to enqueue requests for one time only then we used this WorkRequest.

2. PeriodicWorkRequest

This WorkRequest used for repeating or recurring works. In Simple words, PeriodicWorkRequest works as cron job in android. In other words, you want to perform some repetitive task in Android than we use PeriodicWorkRequest. This type of work is repeating multiple times until it is cancelled. The first execution happening immediately or given Constraints. The next execution will happen as per the given interval. The minimum interval should be 15 min. It can be delayed due to OS battery optimizations and Not meeting all Constraints, such as doze mode, no network connectivity etc.

Understand with Demo Application for cron job in android

1. Let’s open android studio and create a new projects.

Now I’m going to demonstrate, how to scheduling recurring task in Android? How to enqueue the job and cancel the enqueue work? Go to file menu and create a new project with EmptyActivity template and add WorkManager dependency.

  implementation "android.arch.work:work-runtime:1.0.1"

2. Create a subclass of Worker class

Create a java class in src folder and extends Worker class. After that doWork() override methods and define work here.

package com.wave.periodicworkrequest;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;

import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

public class MyWorker extends Worker {
    private static final String WORK_RESULT = "work_result";


    public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {
        Data taskData = getInputData();
        String taskDataString = taskData.getString(MainActivity.MESSAGE_STATUS);

        showNotification("WorkManager", taskDataString != null ? taskDataString : "Message has been Sent");

        Data outputData = new Data.Builder().putString(WORK_RESULT, "Jobs Finished").build();

        return Result.success(outputData);

    }

    private void showNotification(String task, String desc) {

        NotificationManager manager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);


        String channelId = "task_channel";
        String channelName = "task_name";

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            NotificationChannel channel = new
                    NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
            manager.createNotificationChannel(channel);
        }

        NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), channelId)
                .setContentTitle(task)
                .setContentText(desc)
                .setSmallIcon(R.mipmap.ic_launcher);

        manager.notify(1, builder.build());

    }

}
3. Go to res/layout and open activity_main.xml

In this layout we are using three resource, TextView for showing status of work. One Button for enqueue work, second one for cancelling enqueue work. open layout file and add below code

<TextView
    android:id="@+id/textViewWorkStatus"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:text="Work Status"
    app:layout_constraintBottom_toTopOf="@+id/buttonEnqueueWork"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_chainStyle="packed" />

<Button
    android:id="@+id/buttonEnqueueWork"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="16dp"
    android:layout_marginEnd="8dp"
    android:background="@color/colorAccent"
    android:padding="16dp"
    android:text="Enqueue Work"
    android:textAllCaps="false"
    android:textColor="#fff"
    app:layout_constraintBottom_toTopOf="@+id/buttonCancelWork"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/textViewWorkStatus" />

<Button
    android:id="@+id/buttonCancelWork"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="16dp"
    android:layout_marginEnd="8dp"
    android:background="@color/colorAccent"
    android:padding="16dp"
    android:text="Cancel Work"
    android:textAllCaps="false"
    android:textColor="#fff"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/buttonEnqueueWork" />
5. Open MainActivity and do following operations
  • Get WorkManager instance
  • Create PeriodicWorkRequest
  • Get WorkInfo by Id
  • Enqueue work request
  • Cancel an enqueued work
5.1 Get WorkManager instance
WorkManager mWorkManager = WorkManager.getInstance();
5.2 Create PeriodicWorkRequest

WorkManager provides PeriodicWorkRequest for scheduling recurring and repetitive WorkRequest. It has the following parameter

 PeriodicWorkRequest

For now I’m creating request that be run every 15 min.

  PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(MyWorker.class, 15, TimeUnit.MINUTES).build();
5.3 Get WorkInfo by Id
 mWorkManager.getWorkInfoByIdLiveData(workRequest.getId()).observe(this, new Observer<WorkInfo>() {
            @Override
            public void onChanged(@Nullable WorkInfo workInfo) {
                if (workInfo != null) {
                    WorkInfo.State state = workInfo.getState();
                    tvWorkStatus.append(state.toString() + "\n");

                }
            }
        });
5.4 Enqueue work request
        btnSchedulePeriodicWork.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mWorkManager.enqueue(workRequest);
            }
        });
5.6 Cancel a enqueued work

WorkManager supports several ways to cancel a enqueued work

WorkManager.getInstance().cancelWorkById(workRequest.getId());

Finally source code of MainActivity seems like

package com.wave.periodicworkrequest;

import android.arch.lifecycle.Observer;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.util.concurrent.TimeUnit;

import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;


public class MainActivity extends AppCompatActivity {

    public static final String MESSAGE_STATUS = "MainActivity";

    Button btnEnqueueWork;
    Button btnCancelWork;
    TextView tvWorkStatus;
    PeriodicWorkRequest workRequest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnEnqueueWork = findViewById(R.id.buttonEnqueueWork);
        btnCancelWork = findViewById(R.id.buttonCancelWork);
        tvWorkStatus = findViewById(R.id.textViewWorkStatus);

        final WorkManager mWorkManager = WorkManager.getInstance();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            workRequest = new PeriodicWorkRequest.Builder(MyWorker.class, 15, TimeUnit.MINUTES).build();
        }
        btnEnqueueWork.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mWorkManager.enqueue(workRequest);
            }
        });
        btnCancelWork.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                WorkManager.getInstance().cancelWorkById(workRequest.getId());
            }
        });

        mWorkManager.getWorkInfoByIdLiveData(workRequest.getId()).observe(this, new Observer<WorkInfo>() {
            @Override
            public void onChanged(@Nullable WorkInfo workInfo) {
                if (workInfo != null) {
                    WorkInfo.State state = workInfo.getState();
                    tvWorkStatus.append(state.toString() + "\n");

                }
            }
        });

    }
}

Now run the application and see, our app will the up and running. For verifying your logic, follow the step as per demo app video. If it’s helpful for you, then help me by sharing this post with all your friends who learning android app development.

If you have any queries, feel free to ask them in the comment section below. Happy Coding 🙂

Read out tutorials series on Android Architecture Components

1
Leave a Reply

2000
Pramod

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
This check is not required for
workRequest = new PeriodicWorkRequest.Builder …