Work Manager in Android helps us perform tasks that we need to perform irrespective of whether the app is running or not.
Let’s understand the above line using an example
If you have a news app and you want to check every two hours on your server if there is any new news and you want to know about it so that you will inform the user using the notification that new news is available. You can check by opening the app and all this needs to be done irrespective of whether the app is running or not if I have to put it in simple words I would say that if you have to perform any long-running task in the background you can use Work Manager.
Here are some key features and concepts related to Work Manager.
- Worker class: this is part of the AndroidX “ work “ package and is used to define the actual background task that you want to perform. You need to create a custom class and you need to extend the Worker class and override the method where the actual background will be done.
- Constraint: In this, we will define the constraints under which we want to get our work done e.g. device needs to be connected to the Network, the device needs charging, the Network type like wifi or cellular, the device has to be idle, etc.
- Work request: this is an abstract class that contains multiple configurations like whether you want to run your work one time or periodic.
There are 2 types of work requests:
- One-time work request: if you want the task to be executed only once then you should use OneTimeWorkRequest.
Data inputData = new Data.Builder()
.putString("key", "value")
.build();
// Create a OneTimeWorkRequest for your Worker class
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
.setInputData(inputData) // Pass input data if needed
.addTag("download") // Add a tag for easier identification
.build();
// Enqueue the OneTimeWorkRequest
WorkManager.getInstance(this).enqueue(workRequest);
setInputData(): is used to pass any data needed by the worker. This is optional and depends on your specific use case.
addTag(): is optional but can be useful for identifying or canceling specific tasks later.
enqueue(workRequest) is used to schedule the OneTimeWorkRequest with WorkManager.
- PeriodicWorkRequest: This is used to schedule a task that needs to run periodically at fixed intervals. In a simpler way, we can say that if we want our task to be executed multiple times then we should use PeriodicWorkRequest.
// Define constraints (optional)
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(Constraints.NetworkType.CONNECTED)
.build();
// Create a PeriodicWorkRequest for your Worker class
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(
MyWorker.class,
15, // Repeat interval in hours
TimeUnit.HOURS
)
.setConstraints(constraints) // Set constraints if needed
.addTag("periodicDownload") // Add a tag for easier identification
.build();
// Enqueue the PeriodicWorkRequest
WorkManager.getInstance(this).enqueue(periodicWorkRequest);
}
setConstraints(): is optional but can be used to set constraints on when the periodic work should run. In this example, the work will only run when the device is connected to the internet (CONNECTED).
addTag(): is optional but can be useful for identifying or canceling specific tasks later.enqueue(periodicWorkRequest) is used to schedule the PeriodicWorkRequest with WorkManager.
- Work manager: allows you to schedule tasks that can be deferred and executed at an appropriate time.
Below is the simple flow diagram to represent the work manager’s flow of work.
Steps by Step Implementation.
Create a new project and move to Gradle Scripts > build.gradle(Module: app) and add the below dependency.
implementation "androidx.work:work-runtime:2.7.0"
Add the following code to activity_main.xml file. Here we are creating 2 buttons one for starting the One Time Work Request and the other one for the Periodic Work Request.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/start_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start One Time Work Request" />
<Button
android:id="@+id/start_periodic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Periodic Work Request" />
</LinearLayout>
Create a NotificationHelper class and put the below code into it this class will show the notification to the user.
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
public class NotificationHelper {
private static final String CHANNEL_ID = "work_manager_channel";
private static final String CHANNEL_NAME = "Work Manager Channel";
public static void createNotificationChannel(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
public static void showNotification(Context context, String title, String message) {
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
// Add additional configuration if needed
notificationManager.notify(1, builder.build());
}
}
Creating Worker Class
We will create the worker class that will display the notification but first let’s break down the key components of the worker class:
- Extend the worker class: our custom-created class will extend the worker class and override the default constructor The constructor takes two parameters – Context and WorkerParameters. You need to pass these parameters to the super constructor.
- Override doWork() method: This is the method where you define the actual background work that should be performed. This method is executed on a background thread, so it’s important not to perform any UI-related operations here. In this method, we will call our send notification method
Result: The doWork() method should return a Result object indicating the outcome of the work. You can return Result.success() if the work was successful, Result.failure() if there was a failure, or Result.retry() if the work should be retried.
We will write the code inside the try-catch block to handle any exception. Inside the try block we will call our showNotification() and return the Result.success() and inside the catch block we will return the Result.failure().
import android.content.Context;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
public class ShowNotificationWorker extends Worker {
public ShowNotificationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@NonNull
@Override
public Result doWork() {
Context context = getApplicationContext();
try {
NotificationHelper.showNotification(context,"Work manager", "Work manager started");
return Result.success();
} catch (Throwable throwable) {
return Result.failure();
}
}
}
Let us enqueue the work in our MainActivity
We will first declare the objects for the work manager and button and inside the oncreate() method of activity we will initialize the WorkManager class object and find the IDs for the buttons.
Button start_one,start_periodic;
WorkManager workManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start_one = findViewById(R.id.start_one);
start_periodic = findViewById(R.id.start_periodic);
workManager = WorkManager.getInstance(MainActivity.this);
}
OneTimeWorkRequest
First, we will build the oneTimeWorkRequest with WorkManger. We will set the onClickListener on the button and specify the constraints. The constraints object id basically the set of conditions that need to be fulfilled before the work request can run. In the below request we are specifying 2 constraints one that the app needs to be connected to any network and the second device requires charging.
start_one.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(Constraints.NONE.getRequiredNetworkType()) // Require network connection
.setRequiresCharging(true) // Require device to be charging
.build();
}
});
Building WorkRequest and enqueue it
In this step, we will build the one-time request pass the show notification class and then set the constraints so that the work manager will start the work after all constraints are met and finally enqueue the work request.
public class MainActivity extends AppCompatActivity {
Button start_one,start_periodic;
WorkManager workManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start_one = findViewById(R.id.start_one);
start_periodic = findViewById(R.id.start_periodic);
workManager = WorkManager.getInstance(MainActivity.this);
start_one.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(Constraints.NONE.getRequiredNetworkType()) // Require network connection
.setRequiresCharging(true) // Require device to be charging
.build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(ShowNotificationWorker.class)
.setConstraints(constraints)
.build();
workManager.enqueue(workRequest);
}
});
}
}
We have created a one-time request
PeriodicWorkRequest
In this, we will build the periodic work request with the work manager
We first will set the click listener and set the constraints that the device must be charging and must be connected to the network and we will build the PeriodicWorkRequest and enqueue it
- Worker Class: we will pass the worker class we have created
- Pass the repeat interval we will be passing 24
- Pass the time unit for repeat interval
After the constraints are set so that all the constraints are met only then the work manager will run and finally we are building it and we will enqueue the Work Request.
start_periodic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) // Require network connection
.setRequiresCharging(true) // Require device to be charging
.build();
// Create a PeriodicWorkRequest with constraints for PeriodicDownloadWorker
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(
ShowNotificationWorker.class,
24, // Repeat interval in hours
TimeUnit.HOURS
)
.setConstraints(constraints)
.build();
// Enqueue the periodic work request
WorkManager.getInstance(MainActivity.this).enqueue(periodicWorkRequest);
}
});
We have created the periodic request
Below is the full code of MainActivty.java class.
import androidx.appcompat.app.AppCompatActivity;
import androidx.work.Constraints;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity {
Button start_one,start_periodic;
WorkManager workManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start_one = findViewById(R.id.start_one);
start_periodic = findViewById(R.id.start_periodic);
workManager = WorkManager.getInstance(MainActivity.this);
start_one.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) // Require network connection
.setRequiresCharging(true) // Require device to be charging
.build();
OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(ShowNotificationWorker.class)
.setConstraints(constraints)
.build();
workManager.enqueue(workRequest);
}
});
start_periodic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) // Require network connection
.setRequiresCharging(true) // Require device to be charging
.build();
// Create a PeriodicWorkRequest with constraints for PeriodicDownloadWorker
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(
ShowNotificationWorker.class,
24, // Repeat interval in hours
TimeUnit.HOURS
)
.setConstraints(constraints)
.build();
// Enqueue the periodic work request
WorkManager.getInstance(MainActivity.this).enqueue(periodicWorkRequest);
}
});
}
}
Leave a Reply