In the previous blog, I have explained about WorkManager. We understand the needs, uses and implementation of WorkManager. Now I gonna explain, how to running tasks under specific condition using android WorkManager Constraints. You can specify constraint when work should run.
For example, you might want to specify the tasks should run only when
Let’s take an example and understand how to apply the constraint to running a task under a specific condition. I continuing the previous article demo project. That article, We were generates a notification of button onClick() event. Now we will apply the constraint. Before moving ahead we have to understand which one constraint provide by WorkManager.
Running Tasks Under Specific Conditions Sample App
WorkManager Constraints
WorkManager constraints specify the requirement that needs to be met before being executed task. In other words, you can say constraints specify the condition for running task under that specific condition. These constraints can be related to storage, battery or network.
The followings Constraints provides by WorkManager
- requiresStorageNotLow()
- requiresBatteryNotLow()
- requiresCharging()
- requiresDeviceIdle()
- getRequiredNetworkType(): you can specify the NetworkType
The name are suggesting the uses of each.
1. Constraint requiresStorageNotLow()
If you apply this constraint TRUE that the tasks only execute when the storage isn’t low.
Implementation of requiresStorageNotLow()
/** * Constraints * If TRUE task execute only when storage's is not low */ mConstraints = new Constraints.Builder().setRequiresStorageNotLow(true).build(); /** * OneTimeWorkRequest with requiresStorageNotLow Constraints */ mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).setConstraints(mConstraints) .build();
Fetch the task status
/** * Fetch the particular task status using request ID */ mWorkManager.getWorkInfoByIdLiveData(mRequest.getId()).observe(this, new Observer<WorkInfo>() { @Override public void onChanged(@Nullable WorkInfo workInfo) { if (workInfo != null) { WorkInfo.State state = workInfo.getState(); tvStatus.append(state.toString() + "\n"); } } });
Enqueue the WorkRequest
/** * Enqueue the WorkRequest */ mWorkManager.enqueue(mRequest);
Fetch the task status and Enqueue WorkRequest steps same for all WorkRequest.
2. Constraint requiresBatteryNotLow()
public boolean requiresBatteryNotLow () true mean task execute when the battery isn’t low
Implementation requiresBatteryNotLow()
/** * Constraints * If TRUE task execute only when battery isn't low */ mConstraints = new Constraints.Builder().setRequiresBatteryNotLow(true).build(); /** * OneTimeWorkRequest with requiresBatteryNotLow Constraints */ mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).setConstraints(mConstraints) .build();
3. Constraint requiresCharging()
public boolean requiresCharging () is true then task execute while the device is charging
Implementation requiresCharging()
/** * Constraints * If TRUE while the device is charging */ mConstraints = new Constraints.Builder().setRequiresCharging(true).build(); /** * OneTimeWorkRequest with requiresCharging Constraints */ mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).setConstraints(mConstraints) .build();
4. Constraint requiresDeviceIdle()
public boolean requiresDeviceIdle () is true means task only execute while the device is idle. This works after API 23.
Implementation requiresDeviceIdle()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { /** * Constraints * If TRUE while the device is idle */ mConstraints = new Constraints.Builder().setRequiresDeviceIdle(true).build(); /** * OneTimeWorkRequest with requiresDeviceIdle Constraints */ mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).setConstraints(mConstraints) .build(); }
5. Constraint getRequiredNetworkType()
public NetworkType getRequiredNetworkType (), You can you can specify the NetworkType.
NetworkType is
- CONNECTED – Any working network connection is required for this task
- METERED – A metered network connection is required for this task.
- NOT_REQUIRED – A network is not required for this task.
- NOT_ROAMING – A non-roaming network connection is required for this task.
- UNMETERED – An unmetered network connection is required for this task.
Implementation getRequiredNetworkType()
/** * Constraints * Network type is conneted */ mConstraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build(); /** * OneTimeWorkRequest with requiredNetworkType Connected Constraints */ mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).setConstraints(mConstraints) .build();
Constraint Implementation Demo
Let move to AndroidStudio, and open our previous articles project. We build all types of constraint using Constraints
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout 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" tools:context=".MainActivity" > <TextView android:id="@+id/tvStatus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:gravity="center" android:text="Result display here" android:textSize="18sp" app:layout_constraintBottom_toTopOf="@+id/btnSend" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" /> <Button android:id="@+id/btnSend" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" android:layout_marginTop="16dp" android:background="@color/colorAccent" android:paddingLeft="8dp" android:paddingRight="8dp" android:text="Send Notification without Constraints" android:textAllCaps="false" android:textColor="#fff" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tvStatus" /> <Button android:id="@+id/buttonStorageNotLow" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" android:layout_marginTop="8dp" android:background="@color/colorAccent" android:text="Send Notification with requiresStorageNotLow()" android:textAllCaps="false" android:textColor="#fff" app:layout_constraintBottom_toTopOf="@+id/buttonBatteryNotLow" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/btnSend" /> <Button android:id="@+id/buttonBatteryNotLow" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" android:layout_marginTop="8dp" android:background="@color/colorAccent" android:text="Send Notification with requiresBatteryNotLow()" android:textAllCaps="false" android:textColor="#fff" app:layout_constraintBottom_toTopOf="@+id/buttonRequiresCharging" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/buttonStorageNotLow" /> <Button android:id="@+id/buttonRequiresCharging" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" android:layout_marginTop="8dp" android:background="@color/colorAccent" android:text="Send Notification with requiresCharging()" android:textAllCaps="false" android:textColor="#fff" app:layout_constraintBottom_toTopOf="@+id/buttonDeviceIdle" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/buttonBatteryNotLow" /> <Button android:id="@+id/buttonDeviceIdle" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" android:layout_marginTop="8dp" android:background="@color/colorAccent" android:text="Send Notification with requiresDeviceIdle()" android:textAllCaps="false" android:textColor="#fff" app:layout_constraintBottom_toTopOf="@+id/buttonNetworkType" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/buttonRequiresCharging" /> <Button android:id="@+id/buttonNetworkType" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginBottom="32dp" android:layout_marginEnd="16dp" android:layout_marginStart="16dp" android:layout_marginTop="8dp" android:background="@color/colorAccent" android:text="Send Notification with getRequiredNetworkType()" android:textAllCaps="false" android:textColor="#fff" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/buttonDeviceIdle" /> </android.support.constraint.ConstraintLayout>
Open the MainActivity and setOnClick listener of each button.
After adding buttons in activity_main.xml, In MainActivity find the button
The Full Source Code of MainActivity
package com.wave.workmanagerexample; 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 androidx.work.Constraints; import androidx.work.NetworkType; import androidx.work.OneTimeWorkRequest; import androidx.work.WorkInfo; import androidx.work.WorkManager; public class MainActivity extends AppCompatActivity implements View.OnClickListener { public static final String MESSAGE_STATUS = "message_status"; TextView tvStatus; Button btnSend, btnStorageNotLow, btnBatteryNotLow, btnRequiresCharging, btnDeviceIdle, btnNetworkType; OneTimeWorkRequest mRequest; WorkManager mWorkManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); tvStatus = findViewById(R.id.tvStatus); btnSend = findViewById(R.id.btnSend); mWorkManager = WorkManager.getInstance(); } private void initViews() { tvStatus = findViewById(R.id.tvStatus); btnSend = findViewById(R.id.btnSend); btnStorageNotLow = findViewById(R.id.buttonStorageNotLow); btnBatteryNotLow = findViewById(R.id.buttonBatteryNotLow); btnRequiresCharging = findViewById(R.id.buttonRequiresCharging); btnDeviceIdle = findViewById(R.id.buttonDeviceIdle); btnNetworkType = findViewById(R.id.buttonNetworkType); btnSend.setOnClickListener(this); btnStorageNotLow.setOnClickListener(this); btnBatteryNotLow.setOnClickListener(this); btnRequiresCharging.setOnClickListener(this); btnDeviceIdle.setOnClickListener(this); btnNetworkType.setOnClickListener(this); } @Override public void onClick(View v) { tvStatus.setText(""); Constraints mConstraints; switch (v.getId()) { case R.id.btnSend: mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).build(); break; case R.id.buttonStorageNotLow: /** * Constraints * If TRUE task execute only when storage's is not low */ mConstraints = new Constraints.Builder().setRequiresStorageNotLow(true).build(); /** * OneTimeWorkRequest with requiresStorageNotLow Constraints */ mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).setConstraints(mConstraints) .build(); break; case R.id.buttonBatteryNotLow: /** * Constraints * If TRUE task execute only when battery isn't low */ mConstraints = new Constraints.Builder().setRequiresBatteryNotLow(true).build(); /** * OneTimeWorkRequest with requiresBatteryNotLow Constraints */ mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).setConstraints(mConstraints) .build(); break; case R.id.buttonRequiresCharging: /** * Constraints * If TRUE while the device is charging */ mConstraints = new Constraints.Builder().setRequiresCharging(true).build(); /** * OneTimeWorkRequest with requiresCharging Constraints */ mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).setConstraints(mConstraints) .build(); break; case R.id.buttonDeviceIdle: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { /** * Constraints * If TRUE while the device is idle */ mConstraints = new Constraints.Builder().setRequiresDeviceIdle(true).build(); /** * OneTimeWorkRequest with requiresDeviceIdle Constraints */ mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).setConstraints(mConstraints) .build(); } break; case R.id.buttonNetworkType: /** * Constraints * Network type is conneted */ mConstraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build(); /** * OneTimeWorkRequest with requiredNetworkType Connected Constraints */ mRequest = new OneTimeWorkRequest.Builder(NotificationWorker.class).setConstraints(mConstraints) .build(); break; default: break; } /** * Fetch the particular task status using request ID */ mWorkManager.getWorkInfoByIdLiveData(mRequest.getId()).observe(this, new Observer<WorkInfo>() { @Override public void onChanged(@Nullable WorkInfo workInfo) { if (workInfo != null) { WorkInfo.State state = workInfo.getState(); tvStatus.append(state.toString() + "\n"); } } }); /** * Enqueue the WorkRequest */ mWorkManager.enqueue(mRequest); } }
Create a worker class for Notification
package com.wave.workmanagerexample; 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; /** * Created on : Mar 26, 2019 * Author : AndroidWave */ public class NotificationWorker extends Worker { private static final String WORK_RESULT = "work_result"; public NotificationWorker(@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", "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()); } }
Conclusion
Now run the application and see, our app the up and running. Now click each button, For better clarity, you have to use an Android emulator and cross-check constraint. If you have any queries, feel free to ask them in the comment section below. Happy Coding
2 Comments
i did Constraints(While device is chargeing only) at that time Workmanager working fine. After that i was close and open the application again, then unplug from charging , then trigger the work manager (Constraint based work device charging) at that time status showing ENQUEUED status, after that i plug the mobile phone to charging, but status is not changing to SUCCESS . please explain why it is hpaeening. thank you
What happens if the contraint is not satisfied? I would like to show a dialog box that says there is no network connectivty ot low battery when one of the constraints is not met. how to acieve that? Please let me know. thank you.