WorkManager Tutorial for Android: Getting Started

In this WorkManager tutorial for Android, you’ll learn how to create background tasks, how to chain tasks, and how to add constraints to each task. By Fernando Sproviero.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

Observing Work

WorkManager also allows you to observe the progress of each work instance using the following:

  • getStatusById(): Use this to get a LiveData object containing the WorkStatus for the WorkRequest with a given ID.
  • getStatusesByTag(): Returns a LiveData object containing the list of WorkStatus objects for the specified tag. This is possible because you can tag multiple WorkRequests with the same name.
  • getStatusesForUniqueWork(): This will also return a LiveData object containing the list of WorkStatus objects that have the same unique work name.

Tagging a WorkRequest and Observing It

You’ll observe the work of the requests to toggle a progress bar and a cancel button. Open MainActivity and add a tag to the uploadZip work request using a new constant WORK_TAG:

class MainActivity : AppCompatActivity() {

  companion object {
    ...
    private const val WORK_TAG = "WORK_TAG"
  }  


  override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
      ...
      val uploadZip = OneTimeWorkRequest.Builder(UploadWorker::class.java)
          .addTag(WORK_TAG)
          .build()

After you’ve added a tag to the worker, you can observe its status. Now, add the following method to MainActivity, which will do just that:

...
import android.arch.lifecycle.Observer
...

private fun observeWork() {
  val statuses = WorkManager.getInstance().getStatusesByTag(WORK_TAG)
  statuses.observe(this,
      Observer<List<WorkStatus>> { workStatusList ->
        val currentWorkStatus = workStatusList?.getOrNull(0)
        val isWorkActive = currentWorkStatus?.state?.isFinished == false

        val uploadVisibility = if (isWorkActive) View.VISIBLE else View.GONE

        uploadGroup.visibility = uploadVisibility
      })
}

getStatusesByTag() returns a LiveData object to which you attach an Observer. When you get an update on the status from the WorkManager, you check if it’s active or not. Since you’ve tagged only one worker, you can take the first item from the list (if it exists) and check its state. If it’s not finished, you show a progress bar and a cancel button. Otherwise, you hide them.

Now, at the bottom of the onCreate() lifecycle method in MainActivity, add a call observeWork().

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
  initUi()

  requestPermissionsIfNecessary()
    
  observeWork()
}

Checking the Results

Build and run the app. Once you start uploading images, you’ll see the progress bar and the cancel button. The cancel button doesn’t do anything yet, but you’ll fix that soon.

Showing progress bar and cancel button

Canceling Work

WorkManager allows you to cancel work in several ways:

  • Unique work: If you started unique work with a unique work name, then you can just call cancelUniqueWork() and pass the name as parameter.
  • By tag: When you tag one or more WorkRequests, you call cancelAllWorkByTag.
  • By ID: If you have the ID of the WorkRequest and want to cancel it, you call cancelWorkById().

Since you're using unique work, you'll cancel it using the unique work name.

Canceling the Picking Photos Work Sequence

In MainActivity and add the following snippet inside the initUi() method:

cancelButton.setOnClickListener {
    WorkManager.getInstance().cancelUniqueWork(UNIQUE_WORK_NAME)
}

Build and run the app, select some photos and then cancel the work requests using the cancel button.

Understanding Constraints

Some work cannot be done without a certain set of conditions. For example, work may only run if your device is not low on storage, is charging, etc. You can add constraints like these to any of your tasks. It makes sense to add a network-related constraint to the UploadWorker, because you cannot upload unless there is a stable connection.

Adding a Network Connection Constraint

In MainActivity onActivityResult(), modify uploadZip to the following:

val uploadZip = OneTimeWorkRequest.Builder(UploadWorker::class.java)
    .setConstraints(Constraints.Builder().setRequiredNetworkType(
        NetworkType.CONNECTED).build())
    .addTag(WORK_TAG)
    .build()

As you can see, you've configured the upload request to only run if the device is connected to the network, otherwise it will not run until the condition is met. This is really convenient because you don't have to implement the connection listeners and do the checks yourself.

Testing the Network Constraint

Run the app. Set the emulator/device into Airplane mode. Pick photos from your library and open the Logcat console. You should see that the UploadWorker will not run (filter the console for onResponse like you did before and check the timestamp on any results). Only after it receives a network connection will it upload the file. You can make sure this happens by taking a look at the console once again, after disabling Airplane mode.

Where to Go From Here?

Congratulations! You’ve just learned the basics of WorkManager.

You can download the final version of the project using the Download materials button at the top or bottom of this tutorial.

Here are some great references to learn more about the subject:

Feel free to share your feedback, findings or ask any questions in the comments below or in the forums. I hope you enjoyed this tutorial on WorkManager!