Architecture Components

WorkManager Constraints | Running Tasks Under Specific Conditions

Google+ Pinterest LinkedIn Tumblr

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 WorkManager. You can specify constraint when work should run, For example, you might want to specify the tasks should run only when device is connected to the charger or if device is ideal or let’s say downloading the file when device is online, The device is connected with WiFi or Mobile Network. So such constraint can be also implemented using the WorkManager.

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

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
                 */
                Constraints mConstraints = new Constraints.Builder().setRequiresStorageNotLow(true).build();
                /**
                 * OneTimeWorkRequest with  requiresStorageNotLow Constraints
                 */
                OneTimeWorkRequest 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
                 */
                Constraints mConstraints = new Constraints.Builder().setRequiresBatteryNotLow(true).build();
                /**
                 * OneTimeWorkRequest with  requiresBatteryNotLow Constraints
                 */
                OneTimeWorkRequest 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
                 */
                Constraints   mConstraints = new Constraints.Builder().setRequiresCharging(true).build();
                /**
                 * OneTimeWorkRequest with requiresCharging Constraints
                 */
                OneTimeWorkRequest 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
                     */
                    Constraints mConstraints = new Constraints.Builder().setRequiresDeviceIdle(true).build();
                    /**
                     * OneTimeWorkRequest with requiresDeviceIdle Constraints
                     */
                    OneTimeWorkRequest 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 
                 */
                Constraints mConstraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build();
                /**
                 * OneTimeWorkRequest with requiredNetworkType Connected Constraints
                 */
                OneTimeWorkRequest 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 type constraint using Constraints.Builder class. Let open the activity_main.xml and add for more button for all type constraints request.

<?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_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="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_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        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_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        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_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        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_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        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_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="32dp"
        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 button in activity_main.xml, In MainActivity find the button ids using findViewById() , You can use data binding also. Here we have takes 5 button for all possible constraint. So let’s create OneTimeWorkRequest for each constraint.

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);

    }
}

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

Read our tutorials series on Android Architecture Components

Author

Write A Comment