Once you've [defined your
`Worker`](https://developer.android.com/topic/libraries/architecture/workmanager/basics#define_the_work) and
[your `WorkRequest`](https://developer.android.com/topic/libraries/architecture/workmanager/how-to/define-work),
the last step is to enqueue your work. The simplest way to enqueue work
is to call the WorkManager `enqueue()` method, passing the `WorkRequest` you
want to run.  

### Kotlin

    val myWork: WorkRequest = // ... OneTime or PeriodicWork
    WorkManager.getInstance(requireContext()).enqueue(myWork)

### Java

    WorkRequest myWork = // ... OneTime or PeriodicWork
    WorkManager.getInstance(requireContext()).enqueue(myWork);

Use caution when enqueuing work to avoid duplication.
For example, an app might try to upload
its logs to a backend service every 24 hours. If you aren't careful, you might
end up enqueuing the same task many times, even though the job only needs to
run once.
To achieve this goal, you can schedule the work as [unique work](https://developer.android.com/develop/background-work/background-tasks/persistent/how-to/manage-work#unique-work).

## Unique Work

Unique work is a powerful concept that guarantees that you only have one
instance of work with a particular *name* at a time. Unlike IDs, unique names
are human-readable and specified by the developer instead of being
auto-generated by WorkManager. Unlike [tags](https://developer.android.com/topic/libraries/architecture/workmanager/how-to/define-work#tag), unique names are only
associated with a single instance of work.

Unique work can be applied to both one-time and periodic work. You can create a
unique work sequence by calling one of these methods, depending on whether
you're scheduling repeating work or one time work.

- [`WorkManager.enqueueUniqueWork()`](https://developer.android.com/reference/androidx/work/WorkManager#enqueueUniqueWork(kotlin.String,androidx.work.ExistingWorkPolicy,androidx.work.OneTimeWorkRequest)) for one time work
- [`WorkManager.enqueueUniquePeriodicWork()`](https://developer.android.com/reference/androidx/work/WorkManager#enqueueUniquePeriodicWork(kotlin.String,%20androidx.work.ExistingPeriodicWorkPolicy,%20androidx.work.PeriodicWorkRequest)) for periodic work

Both of these methods accept 3 arguments:

- <var translate="no">uniqueWorkName</var> - A `String` used to uniquely identify the work request.
- <var translate="no">existingWorkPolicy</var> - An `enum` which tells WorkManager what to do if there's already an unfinished chain of work with that unique name. See [conflict resolution policy](https://developer.android.com/develop/background-work/background-tasks/persistent/how-to/manage-work#conflict-resolution) for more information.
- <var translate="no">work</var> - the `WorkRequest` to schedule.

Using unique work, we can fix our duplicate scheduling issue noted earlier.  

### Kotlin

    val sendLogsWorkRequest =
           PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS)
               .setConstraints(Constraints.Builder()
                   .setRequiresCharging(true)
                   .build()
                )
               .build()
    WorkManager.getInstance(this).enqueueUniquePeriodicWork(
               "sendLogs",
               ExistingPeriodicWorkPolicy.KEEP,
               sendLogsWorkRequest
    )

### Java

    PeriodicWorkRequest sendLogsWorkRequest = new
          PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS)
                  .setConstraints(new Constraints.Builder()
                  .setRequiresCharging(true)
              .build()
          )
         .build();
    WorkManager.getInstance(this).enqueueUniquePeriodicWork(
         "sendLogs",
         ExistingPeriodicWorkPolicy.KEEP,
         sendLogsWorkRequest);

Now, if the code runs while a sendLogs job is already in the queue, the existing
job is kept and no new job is added.

Unique work sequences can also be useful if you need to gradually build up a
long chain of tasks. For example, a photo editing app might let users undo a
long chain of actions. Each of those undo operations might take a while, but
they have to be performed in the correct order. In this case, the app could
create an "undo" chain and append each undo operation to the chain as needed.
See [Chaining work](https://developer.android.com/topic/libraries/architecture/workmanager/how-to/chain-work)
for more details.

### Conflict resolution policy

When scheduling unique work, you must tell WorkManager what action to take when
there is a conflict. You do this by passing an enum when enqueuing the work.

For one-time work, you provide an
[`ExistingWorkPolicy`](https://developer.android.com/reference/androidx/work/ExistingWorkPolicy), which
supports 4 options for handling the conflict.

- [`REPLACE`](https://developer.android.com/reference/androidx/work/ExistingWorkPolicy#REPLACE) existing work with the new work. This option cancels the existing work.
- [`KEEP`](https://developer.android.com/reference/androidx/work/ExistingWorkPolicy#KEEP) existing work and ignore the new work.
- [`APPEND`](https://developer.android.com/reference/androidx/work/ExistingWorkPolicy#APPEND) the new work to the end of the existing work. This policy will cause your new work to be [chained](https://developer.android.com/topic/libraries/architecture/workmanager/how-to/chain-work) to the existing work, running after the existing work finishes.

The existing work becomes a *prerequisite* to the new work. If the existing work
becomes `CANCELLED` or `FAILED`, the new work is also `CANCELLED` or `FAILED`.
If you want the new work to run regardless of the status of the existing work,
use `APPEND_OR_REPLACE` instead.

- [`APPEND_OR_REPLACE`](https://developer.android.com/reference/androidx/work/ExistingWorkPolicy#APPEND) functions similarly to `APPEND`, except that it is not dependent on ***prerequisite*** work status. If the existing work is `CANCELLED` or `FAILED`, the new work still runs.

For period work, you provide an
[`ExistingPeriodicWorkPolicy`](https://developer.android.com/reference/androidx/work/ExistingPeriodicWorkPolicy),
which supports 2 options, `REPLACE` and `KEEP`. These options function the same
as their ExistingWorkPolicy counterparts.

## Observing your work

At any point after enqueuing work, you can check its status by querying
WorkManager by its `name`, `id` or by a `tag` associated with it.  

### Kotlin

    // by id
    workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>

    // by name
    workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>

    // by tag
    workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>

### Java

    // by id
    workManager.getWorkInfoById(syncWorker.id); // ListenableFuture<WorkInfo>

    // by name
    workManager.getWorkInfosForUniqueWork("sync"); // ListenableFuture<List<WorkInfo>>

    // by tag
    workManager.getWorkInfosByTag("syncTag"); // ListenableFuture<List<WorkInfo>>

The query returns a
[`ListenableFuture`](https://guava.dev/releases/23.1-android/api/docs/com/google/common/util/concurrent/ListenableFuture.html)
of a [`WorkInfo`](https://developer.android.com/reference/androidx/work/WorkInfo) object, which includes the
[`id`](https://developer.android.com/reference/androidx/work/WorkInfo#getId()) of the work, its tags, its
current [`State`](https://developer.android.com/reference/androidx/work/WorkInfo.State), and any output dataset using
[`Result.success(outputData)`](https://developer.android.com/reference/androidx/work/ListenableWorker.Result#success(androidx.work.Data)).

The [`LiveData`](https://developer.android.com/topic/libraries/architecture/livedata) and [`Flow`](https://developer.android.com/kotlin/flow)
variants of each of the methods lets you *observe changes to the
`WorkInfo`* by registering a listener. For example, if you wanted to display
a message to the user when some work finishes successfully, you could set it up
as follows:  

### Kotlin

    workManager.getWorkInfoByIdFlow(syncWorker.id)
              .collect{ workInfo ->
                  if(workInfo?.state == WorkInfo.State.SUCCEEDED) {
                      Snackbar.make(requireView(),
                          R.string.work_completed, Snackbar.LENGTH_SHORT)
                          .show()
                  }
              }

### Java

    workManager.getWorkInfoByIdLiveData(syncWorker.id)
            .observe(getViewLifecycleOwner(), workInfo -> {
        if (workInfo.getState() != null &&
                workInfo.getState() == WorkInfo.State.SUCCEEDED) {
            Snackbar.make(requireView(),
                        R.string.work_completed, Snackbar.LENGTH_SHORT)
                    .show();
       }
    });

### Complex work queries

WorkManager 2.4.0 and higher supports complex querying for enqueued jobs using
[`WorkQuery`](https://developer.android.com/reference/androidx/work/WorkQuery) objects. WorkQuery supports
querying for work by a combination of its tag(s), state and unique work name.

The following example shows how you can find all work with the tag, *"syncTag"* ,
that is in the `FAILED` or `CANCELLED` state and has a unique work name of
either "*preProcess* " or "*sync*".  

### Kotlin

    val workQuery = WorkQuery.Builder
           .fromTags(listOf("syncTag"))
           .addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
           .addUniqueWorkNames(listOf("preProcess", "sync")
        )
       .build()

    val workInfos: ListenableFuture<List<WorkInfo>> = workManager.getWorkInfos(workQuery)

### Java

    WorkQuery workQuery = WorkQuery.Builder
           .fromTags(Arrays.asList("syncTag"))
           .addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
           .addUniqueWorkNames(Arrays.asList("preProcess", "sync")
         )
        .build();

    ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);

Each component (tag, state, or name) in a `WorkQuery` is `AND`-ed with the
others. Each value in a component is `OR`-ed. For example: `(name1 OR name2
OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)`.

`WorkQuery` also works with the LiveData equivalent,
[`getWorkInfosLiveData()`](https://developer.android.com/reference/androidx/work/WorkManager#getWorkInfosLiveData(androidx.work.WorkQuery)),
and the Flow equivalent, [`getWorkInfosFlow()`](https://developer.android.com/reference/androidx/work/WorkManager#getWorkInfosFlow(androidx.work.WorkQuery)).

## Cancelling and stopping work

If you no longer need your previously enqueued work to run, you can ask for it
to be cancelled. Work can be cancelled by its `name`, `id` or by a `tag`
associated with it.  

### Kotlin

    // by id
    workManager.cancelWorkById(syncWorker.id)

    // by name
    workManager.cancelUniqueWork("sync")

    // by tag
    workManager.cancelAllWorkByTag("syncTag")

### Java

    // by id
    workManager.cancelWorkById(syncWorker.id);

    // by name
    workManager.cancelUniqueWork("sync");

    // by tag
    workManager.cancelAllWorkByTag("syncTag");

Under the hood, WorkManager checks the
[`State`](https://developer.android.com/reference/androidx/work/WorkInfo.State) of the work. If the work is
already [finished](https://developer.android.com/reference/androidx/work/WorkInfo.State#isFinished()),
nothing happens. Otherwise, the work's state is changed to
[`CANCELLED`](https://developer.android.com/reference/androidx/work/WorkInfo.State#CANCELLED) and the work
will not run in the future. Any
[`WorkRequest`](https://developer.android.com/reference/androidx/work/WorkRequest) jobs that are [dependent
on this work](https://developer.android.com/topic/libraries/architecture/workmanager/how-to/chain-work) will
also be `CANCELLED`.

[`RUNNING`](https://developer.android.com/reference/androidx/work/WorkInfo.State#RUNNING) work
receives a call to
[`ListenableWorker.onStopped()`](https://developer.android.com/reference/androidx/work/ListenableWorker#onStopped()).
Override this method to handle any potential cleanup. See [stop a
running worker](https://developer.android.com/develop/background-work/background-tasks/persistent/how-to/manage-work#stop-worker) for more information.
| **Note:** [`cancelAllWorkByTag(String)`](https://developer.android.com/reference/androidx/work/WorkManager#cancelAllWorkByTag(java.lang.String)) cancels *all* work with the given tag.

## Stop a running Worker

There are a few different reasons your running `Worker` might be stopped by
WorkManager:

- You explicitly asked for it to be cancelled (by calling `WorkManager.cancelWorkById(UUID)`, for example).
- In the case of [unique work](https://developer.android.com/develop/background-work/background-tasks/persistent/how-to/manage-work#unique-work), you explicitly enqueued a new `WorkRequest` with an [`ExistingWorkPolicy`](https://developer.android.com/reference/androidx/work/ExistingWorkPolicy) of [`REPLACE`](https://developer.android.com/reference/androidx/work/ExistingWorkPolicy#REPLACE). The old `WorkRequest` is immediately considered cancelled.
- Your work's constraints are no longer met.
- The system instructed your app to stop your work for some reason. This can happen if you exceed the execution deadline of 10 minutes. The work is scheduled for retry at a later time.

Under these conditions, your Worker is stopped.

You should cooperatively abort any work you had in progress and release any
resources your Worker is holding onto. For example, you should close open
handles to databases and files at this point. There are two mechanisms at your
disposal to understand when your Worker is stopping.

### onStopped() callback

WorkManager invokes
[`ListenableWorker.onStopped()`](https://developer.android.com/reference/androidx/work/ListenableWorker#onStopped())
as soon as your Worker has been stopped. Override this method to close
any resources you may be holding onto.

#### isStopped() property

You can call the
[`ListenableWorker.isStopped()`](https://developer.android.com/reference/androidx/work/ListenableWorker#isStopped()) method to check if your worker has already
been stopped. If you're performing long-running or repetitive operations in your
Worker, you should check this property frequently and use it as a signal for
stopping work as soon as possible.

**Note:** WorkManager ignores the
[`Result`](https://developer.android.com/reference/androidx/work/ListenableWorker.Result) set by a Worker
that has received the *onStop* signal, because the Worker is already considered
stopped.