blob: 5960e50fcab2fa5063aaacc140471280781fea2f [file] [log] [blame]
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.work;
import android.arch.lifecycle.LiveData;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;
import androidx.work.impl.WorkManagerImpl;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* WorkManager is a library used to enqueue work that is guaranteed to execute after its constraints
* are met. WorkManager allows observation of work status and the ability to create complex chains
* of work.
* <p>
* WorkManager uses an underlying job dispatching service when available based on the following
* criteria:
* <p><ul>
* <li>Uses JobScheduler for API 23+
* <li>For API 14-22
* <ul>
* <li>If using Firebase JobDispatcher in the app and the optional Firebase dependency, uses
* Firebase JobDispatcher
* <li>Otherwise, uses a custom AlarmManager + BroadcastReceiver implementation
* </ul></ul>
* <p></p>All work must have a corresponding {@link Worker} to perform the computations. Work is
* performed in the background thread.
*
* <p>There are two types of work supported by WorkManager: {@link OneTimeWorkRequest} and
* {@link PeriodicWorkRequest}. You can enqueue requests using WorkManager as follows:
*
* <pre>
* {@code
* WorkManager workManager = WorkManager.getInstance();
* workManager.enqueue(new OneTimeWorkRequest.Builder(FooWorker.class).build());}</pre>
*
* A {@link WorkRequest} has an associated id that can be used for lookups and observation as
* follows:
*
* <pre>
* {@code
* WorkRequest request = new OneTimeWorkRequest.Builder(FooWorker.class).build();
* workManager.enqueue(request);
* LiveData<WorkStatus> status = workManager.getStatusById(request.getId());
* status.observe(...);}</pre>
*
* You can also use the id for cancellation:
*
* <pre>
* {@code
* WorkRequest request = new OneTimeWorkRequest.Builder(FooWorker.class).build();
* workManager.enqueue(request);
* workManager.cancelWorkById(request.getId());}</pre>
*
* You can chain work as follows:
*
* <pre>
* {@code
* WorkRequest request1 = new OneTimeWorkRequest.Builder(FooWorker.class).build();
* WorkRequest request2 = new OneTimeWorkRequest.Builder(BarWorker.class).build();
* WorkRequest request3 = new OneTimeWorkRequest.Builder(BazWorker.class).build();
* workManager.beginWith(request1, request2).then(request3).enqueue();}</pre>
*
* Each call to {@link #beginWith(OneTimeWorkRequest...)} or {@link #beginWith(List)} returns a
* {@link WorkContinuation} upon which you can call
* {@link WorkContinuation#then(OneTimeWorkRequest...)} or {@link WorkContinuation#then(List)} to
* chain further work. This allows for creation of complex chains of work. For example, to create
* a chain like this:
*
* <pre>
* A
* |
* +----------+
* | |
* B C
* |
* +----+
* | |
* D E </pre>
*
* you would enqueue them as follows:
*
* <pre>
* {@code
* WorkContinuation continuation = workManager.beginWith(A);
* continuation.then(B).then(D, E).enqueue(); // A is implicitly enqueued here
* continuation.then(C).enqueue();}</pre>
*
* WorkRequests can accept {@link Constraints}, inputs (see {@link Data}), and backoff criteria.
* WorkRequests can be tagged with human-readable Strings
* (see {@link WorkRequest.Builder#addTag(String)}), and chains of work can be given a
* uniquely-identifiable name (see
* {@link #beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest...)}).
*
* <p>By default, WorkManager runs its operations on a background thread. If you are already
* running on a background thread and have need for synchronous (blocking) calls to WorkManager, use
* {@link #synchronous()} to access such methods.
*/
public abstract class WorkManager {
/**
* Retrieves the {@code default} singleton instance of {@link WorkManager}.
*
* @return The singleton instance of {@link WorkManager}
*/
public static WorkManager getInstance() {
return WorkManagerImpl.getInstance();
}
/**
* Used to do a one-time initialization of the {@link WorkManager} singleton with the default
* configuration.
*
* @param context A {@link Context} object for configuration purposes. Internally, this class
* will call {@link Context#getApplicationContext()}, so you may safely pass in
* any Context without risking a memory leak.
* @param configuration The {@link Configuration} for used to set up WorkManager.
*/
public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
WorkManagerImpl.initialize(context, configuration);
}
/**
* Enqueues one or more items for background processing.
*
* @param workRequests One or more {@link WorkRequest} to enqueue
*/
public final void enqueue(@NonNull WorkRequest... workRequests) {
enqueue(Arrays.asList(workRequests));
}
/**
* Enqueues one or more items for background processing.
*
* @param workRequests One or more {@link WorkRequest} to enqueue
*/
public abstract void enqueue(@NonNull List<? extends WorkRequest> workRequests);
/**
* Begins a chain of {@link OneTimeWorkRequest}, which can be enqueued together in the future
* using {@link WorkContinuation#enqueue()}.
*
* @param work One or more {@link OneTimeWorkRequest} to start a chain of work
* @return A {@link WorkContinuation} that allows for further chaining of dependent
* {@link OneTimeWorkRequest}
*/
public final WorkContinuation beginWith(@NonNull OneTimeWorkRequest...work) {
return beginWith(Arrays.asList(work));
}
/**
* Begins a chain of {@link OneTimeWorkRequest}, which can be enqueued together in the future
* using {@link WorkContinuation#enqueue()}.
*
* @param work One or more {@link OneTimeWorkRequest} to start a chain of work
* @return A {@link WorkContinuation} that allows for further chaining of dependent
* {@link OneTimeWorkRequest}
*/
public abstract WorkContinuation beginWith(@NonNull List<OneTimeWorkRequest> work);
/**
* This method allows you to begin unique chains of work for situations where you only want one
* chain with a given name to be active at a time. For example, you may only want one sync
* operation to be active. If there is one pending, you can choose to let it run or replace it
* with your new work.
*
* The {@code uniqueWorkName} uniquely identifies this set of work.
*
* If this method determines that new work should be enqueued and run, all records of previous
* work with {@code uniqueWorkName} will be pruned. If this method determines that new work
* should NOT be run, then the entire chain will be considered a no-op.
*
* @param uniqueWorkName A unique name which for this chain of work
* @param existingWorkPolicy An {@link ExistingWorkPolicy}
* @param work One or more {@link OneTimeWorkRequest} to enqueue. {@code REPLACE} ensures that
* if there is pending work labelled with {@code uniqueWorkName}, it will be
* cancelled and the new work will run. {@code KEEP} will run the new sequence of
* work only if there is no pending work labelled with {@code uniqueWorkName}.
* {@code APPEND} will create a new sequence of work if there is no
* existing work with {@code uniqueWorkName}; otherwise, {@code work} will be added
* as a child of all leaf nodes labelled with {@code uniqueWorkName}.
* @return A {@link WorkContinuation} that allows further chaining
*/
public final WorkContinuation beginUniqueWork(
@NonNull String uniqueWorkName,
@NonNull ExistingWorkPolicy existingWorkPolicy,
@NonNull OneTimeWorkRequest... work) {
return beginUniqueWork(uniqueWorkName, existingWorkPolicy, Arrays.asList(work));
}
/**
* This method allows you to begin unique chains of work for situations where you only want one
* chain with a given name to be active at a time. For example, you may only want one sync
* operation to be active. If there is one pending, you can choose to let it run or replace it
* with your new work.
*
* The {@code uniqueWorkName} uniquely identifies this set of work.
*
* If this method determines that new work should be enqueued and run, all records of previous
* work with {@code uniqueWorkName} will be pruned. If this method determines that new work
* should NOT be run, then the entire chain will be considered a no-op.
*
* @param uniqueWorkName A unique name which for this chain of work
* @param existingWorkPolicy An {@link ExistingWorkPolicy}
* @param work One or more {@link OneTimeWorkRequest} to enqueue. {@code REPLACE} ensures that
* if there is pending work labelled with {@code uniqueWorkName}, it will be
* cancelled and the new work will run. {@code KEEP} will run the new sequence of
* work only if there is no pending work labelled with {@code uniqueWorkName}.
* {@code APPEND} will create a new sequence of work if there is no
* existing work with {@code uniqueWorkName}; otherwise, {@code work} will be added
* as a child of all leaf nodes labelled with {@code uniqueWorkName}.
* @return A {@link WorkContinuation} that allows further chaining
*/
public abstract WorkContinuation beginUniqueWork(
@NonNull String uniqueWorkName,
@NonNull ExistingWorkPolicy existingWorkPolicy,
@NonNull List<OneTimeWorkRequest> work);
/**
* This method allows you to enqueue a uniquely-named {@link PeriodicWorkRequest}, where only
* one PeriodicWorkRequest of a particular name can be active at a time. For example, you may
* only want one sync operation to be active. If there is one pending, you can choose to let it
* run or replace it with your new work.
*
* The {@code uniqueWorkName} uniquely identifies this PeriodicWorkRequest.
*
* @param uniqueWorkName A unique name which for this operation
* @param existingPeriodicWorkPolicy An {@link ExistingPeriodicWorkPolicy}
* @param periodicWork A {@link PeriodicWorkRequest} to enqueue. {@code REPLACE} ensures that if
* there is pending work labelled with {@code uniqueWorkName}, it will be
* cancelled and the new work will run. {@code KEEP} will run the new
* PeriodicWorkRequest only if there is no pending work labelled with
* {@code uniqueWorkName}.
*/
public abstract void enqueueUniquePeriodicWork(
@NonNull String uniqueWorkName,
@NonNull ExistingPeriodicWorkPolicy existingPeriodicWorkPolicy,
@NonNull PeriodicWorkRequest periodicWork);
/**
* Cancels work with the given id if it isn't finished. Note that cancellation is a best-effort
* policy and work that is already executing may continue to run.
*
* @param id The id of the work
*/
public abstract void cancelWorkById(@NonNull UUID id);
/**
* Cancels all unfinished work with the given tag. Note that cancellation is a best-effort
* policy and work that is already executing may continue to run.
*
* @param tag The tag used to identify the work
*/
public abstract void cancelAllWorkByTag(@NonNull String tag);
/**
* Cancels all unfinished work in the work chain with the given name. Note that cancellation is
* a best-effort policy and work that is already executing may continue to run.
*
* @param uniqueWorkName The unique name used to identify the chain of work
*/
public abstract void cancelUniqueWork(@NonNull String uniqueWorkName);
/**
* Cancels all unfinished work. <b>Use this method with extreme caution!</b> By invoking it,
* you will potentially affect other modules or libraries in your codebase. It is strongly
* recommended that you use one of the other cancellation methods at your disposal.
*/
public abstract void cancelAllWork();
/**
* Prunes all eligible finished work from the internal database. Eligible work must be finished
* ({@link State#SUCCEEDED}, {@link State#FAILED}, or {@link State#CANCELLED}), with zero
* unfinished dependents.
* <p>
* <b>Use this method with caution</b>; by invoking it, you (and any modules and libraries in
* your codebase) will no longer be able to observe the {@link WorkStatus} of the pruned work.
* You do not normally need to call this method - WorkManager takes care to auto-prune its work
* after a sane period of time. This method also ignores the
* {@link OneTimeWorkRequest.Builder#keepResultsForAtLeast(long, TimeUnit)} policy.
*/
public abstract void pruneWork();
/**
* Gets a {@link LiveData} of the last time all work was cancelled. This method is intended for
* use by library and module developers who have dependent data in their own repository that
* must be updated or deleted in case someone cancels their work without their prior knowledge.
*
* @return A {@link LiveData} of the timestamp in milliseconds when method that cancelled all
* work was last invoked
*/
public abstract LiveData<Long> getLastCancelAllTimeMillis();
/**
* Gets a {@link LiveData} of the {@link WorkStatus} for a given work id.
*
* @param id The id of the work
* @return A {@link LiveData} of the {@link WorkStatus} associated with {@code id}
*/
public abstract LiveData<WorkStatus> getStatusById(@NonNull UUID id);
/**
* Gets a {@link LiveData} of the {@link WorkStatus} for all work for a given tag.
*
* @param tag The tag of the work
* @return A {@link LiveData} list of {@link WorkStatus} for work tagged with {@code tag}
*/
public abstract LiveData<List<WorkStatus>> getStatusesByTag(@NonNull String tag);
/**
* Gets a {@link LiveData} of the {@link WorkStatus} for all work in a work chain with a given
* unique name.
*
* @param uniqueWorkName The unique name used to identify the chain of work
* @return A {@link LiveData} of the {@link WorkStatus} for work in the chain named
* {@code uniqueWorkName}
*/
public abstract LiveData<List<WorkStatus>> getStatusesForUniqueWork(
@NonNull String uniqueWorkName);
/**
* Gets an object that gives access to synchronous methods.
*
* @return A {@link SynchronousWorkManager} object, which gives access to synchronous methods
*/
public abstract SynchronousWorkManager synchronous();
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
protected WorkManager() {
}
}