Home | History | Annotate | Download | only in work
      1 /*
      2  * Copyright 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package androidx.work;
     18 
     19 import android.arch.lifecycle.LiveData;
     20 import android.content.Context;
     21 import android.support.annotation.NonNull;
     22 import android.support.annotation.RestrictTo;
     23 
     24 import androidx.work.impl.WorkManagerImpl;
     25 
     26 import java.util.Arrays;
     27 import java.util.List;
     28 import java.util.UUID;
     29 import java.util.concurrent.TimeUnit;
     30 
     31 /**
     32  * WorkManager is a library used to enqueue work that is guaranteed to execute after its constraints
     33  * are met.  WorkManager allows observation of work status and the ability to create complex chains
     34  * of work.
     35  * <p>
     36  * WorkManager uses an underlying job dispatching service when available based on the following
     37  * criteria:
     38  * <p><ul>
     39  * <li>Uses JobScheduler for API 23+
     40  * <li>For API 14-22
     41  * <ul>
     42  *   <li>If using Firebase JobDispatcher in the app and the optional Firebase dependency, uses
     43  *     Firebase JobDispatcher
     44  *   <li>Otherwise, uses a custom AlarmManager + BroadcastReceiver implementation
     45  * </ul></ul>
     46  * <p></p>All work must have a corresponding {@link Worker} to perform the computations.  Work is
     47  * performed in the background thread.
     48  *
     49  * <p>There are two types of work supported by WorkManager: {@link OneTimeWorkRequest} and
     50  * {@link PeriodicWorkRequest}.  You can enqueue requests using WorkManager as follows:
     51  *
     52  * <pre>
     53  * {@code
     54  * WorkManager workManager = WorkManager.getInstance();
     55  * workManager.enqueue(new OneTimeWorkRequest.Builder(FooWorker.class).build());}</pre>
     56  *
     57  * A {@link WorkRequest} has an associated id that can be used for lookups and observation as
     58  * follows:
     59  *
     60  * <pre>
     61  * {@code
     62  * WorkRequest request = new OneTimeWorkRequest.Builder(FooWorker.class).build();
     63  * workManager.enqueue(request);
     64  * LiveData<WorkStatus> status = workManager.getStatusById(request.getId());
     65  * status.observe(...);}</pre>
     66  *
     67  * You can also use the id for cancellation:
     68  *
     69  * <pre>
     70  * {@code
     71  * WorkRequest request = new OneTimeWorkRequest.Builder(FooWorker.class).build();
     72  * workManager.enqueue(request);
     73  * workManager.cancelWorkById(request.getId());}</pre>
     74  *
     75  * You can chain work as follows:
     76  *
     77  * <pre>
     78  * {@code
     79  * WorkRequest request1 = new OneTimeWorkRequest.Builder(FooWorker.class).build();
     80  * WorkRequest request2 = new OneTimeWorkRequest.Builder(BarWorker.class).build();
     81  * WorkRequest request3 = new OneTimeWorkRequest.Builder(BazWorker.class).build();
     82  * workManager.beginWith(request1, request2).then(request3).enqueue();}</pre>
     83  *
     84  * Each call to {@link #beginWith(OneTimeWorkRequest...)} or {@link #beginWith(List)} returns a
     85  * {@link WorkContinuation} upon which you can call
     86  * {@link WorkContinuation#then(OneTimeWorkRequest...)} or {@link WorkContinuation#then(List)} to
     87  * chain further work.  This allows for creation of complex chains of work.  For example, to create
     88  * a chain like this:
     89  *
     90  * <pre>
     91  *            A
     92  *            |
     93  *      +----------+
     94  *      |          |
     95  *      B          C
     96  *      |
     97  *   +----+
     98  *   |    |
     99  *   D    E             </pre>
    100  *
    101  * you would enqueue them as follows:
    102  *
    103  * <pre>
    104  * {@code
    105  * WorkContinuation continuation = workManager.beginWith(A);
    106  * continuation.then(B).then(D, E).enqueue();  // A is implicitly enqueued here
    107  * continuation.then(C).enqueue();}</pre>
    108  *
    109  * WorkRequests can accept {@link Constraints}, inputs (see {@link Data}), and backoff criteria.
    110  * WorkRequests can be tagged with human-readable Strings
    111  * (see {@link WorkRequest.Builder#addTag(String)}), and chains of work can be given a
    112  * uniquely-identifiable name (see
    113  * {@link #beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest...)}).
    114  *
    115  * <p>By default, WorkManager runs its operations on a background thread.  If you are already
    116  * running on a background thread and have need for synchronous (blocking) calls to WorkManager, use
    117  * {@link #synchronous()} to access such methods.
    118  */
    119 public abstract class WorkManager {
    120 
    121     /**
    122      * Retrieves the {@code default} singleton instance of {@link WorkManager}.
    123      *
    124      * @return The singleton instance of {@link WorkManager}
    125      */
    126     public static WorkManager getInstance() {
    127         return WorkManagerImpl.getInstance();
    128     }
    129 
    130     /**
    131      * Used to do a one-time initialization of the {@link WorkManager} singleton with the default
    132      * configuration.
    133      *
    134      * @param context A {@link Context} object for configuration purposes. Internally, this class
    135      *                will call {@link Context#getApplicationContext()}, so you may safely pass in
    136      *                any Context without risking a memory leak.
    137      * @param configuration The {@link Configuration} for used to set up WorkManager.
    138      */
    139     public static void initialize(@NonNull Context context, @NonNull Configuration configuration) {
    140         WorkManagerImpl.initialize(context, configuration);
    141     }
    142 
    143     /**
    144      * Enqueues one or more items for background processing.
    145      *
    146      * @param workRequests One or more {@link WorkRequest} to enqueue
    147      */
    148     public final void enqueue(@NonNull WorkRequest... workRequests) {
    149         enqueue(Arrays.asList(workRequests));
    150     }
    151 
    152     /**
    153      * Enqueues one or more items for background processing.
    154      *
    155      * @param workRequests One or more {@link WorkRequest} to enqueue
    156      */
    157     public abstract void enqueue(@NonNull List<? extends WorkRequest> workRequests);
    158 
    159     /**
    160      * Begins a chain of {@link OneTimeWorkRequest}, which can be enqueued together in the future
    161      * using {@link WorkContinuation#enqueue()}.
    162      *
    163      * @param work One or more {@link OneTimeWorkRequest} to start a chain of work
    164      * @return A {@link WorkContinuation} that allows for further chaining of dependent
    165      *         {@link OneTimeWorkRequest}
    166      */
    167     public final WorkContinuation beginWith(@NonNull OneTimeWorkRequest...work) {
    168         return beginWith(Arrays.asList(work));
    169     }
    170 
    171     /**
    172      * Begins a chain of {@link OneTimeWorkRequest}, which can be enqueued together in the future
    173      * using {@link WorkContinuation#enqueue()}.
    174      *
    175      * @param work One or more {@link OneTimeWorkRequest} to start a chain of work
    176      * @return A {@link WorkContinuation} that allows for further chaining of dependent
    177      *         {@link OneTimeWorkRequest}
    178      */
    179     public abstract WorkContinuation beginWith(@NonNull List<OneTimeWorkRequest> work);
    180 
    181     /**
    182      * This method allows you to begin unique chains of work for situations where you only want one
    183      * chain with a given name to be active at a time.  For example, you may only want one sync
    184      * operation to be active.  If there is one pending, you can choose to let it run or replace it
    185      * with your new work.
    186      *
    187      * The {@code uniqueWorkName} uniquely identifies this set of work.
    188      *
    189      * If this method determines that new work should be enqueued and run, all records of previous
    190      * work with {@code uniqueWorkName} will be pruned.  If this method determines that new work
    191      * should NOT be run, then the entire chain will be considered a no-op.
    192      *
    193      * @param uniqueWorkName A unique name which for this chain of work
    194      * @param existingWorkPolicy An {@link ExistingWorkPolicy}
    195      * @param work One or more {@link OneTimeWorkRequest} to enqueue. {@code REPLACE} ensures that
    196      *             if there is pending work labelled with {@code uniqueWorkName}, it will be
    197      *             cancelled and the new work will run. {@code KEEP} will run the new sequence of
    198      *             work only if there is no pending work labelled with {@code uniqueWorkName}.
    199      *             {@code APPEND} will create a new sequence of work if there is no
    200      *             existing work with {@code uniqueWorkName}; otherwise, {@code work} will be added
    201      *             as a child of all leaf nodes labelled with {@code uniqueWorkName}.
    202      * @return A {@link WorkContinuation} that allows further chaining
    203      */
    204     public final WorkContinuation beginUniqueWork(
    205             @NonNull String uniqueWorkName,
    206             @NonNull ExistingWorkPolicy existingWorkPolicy,
    207             @NonNull OneTimeWorkRequest... work) {
    208         return beginUniqueWork(uniqueWorkName, existingWorkPolicy, Arrays.asList(work));
    209     }
    210 
    211     /**
    212      * This method allows you to begin unique chains of work for situations where you only want one
    213      * chain with a given name to be active at a time.  For example, you may only want one sync
    214      * operation to be active.  If there is one pending, you can choose to let it run or replace it
    215      * with your new work.
    216      *
    217      * The {@code uniqueWorkName} uniquely identifies this set of work.
    218      *
    219      * If this method determines that new work should be enqueued and run, all records of previous
    220      * work with {@code uniqueWorkName} will be pruned.  If this method determines that new work
    221      * should NOT be run, then the entire chain will be considered a no-op.
    222      *
    223      * @param uniqueWorkName A unique name which for this chain of work
    224      * @param existingWorkPolicy An {@link ExistingWorkPolicy}
    225      * @param work One or more {@link OneTimeWorkRequest} to enqueue. {@code REPLACE} ensures that
    226      *             if there is pending work labelled with {@code uniqueWorkName}, it will be
    227      *             cancelled and the new work will run. {@code KEEP} will run the new sequence of
    228      *             work only if there is no pending work labelled with {@code uniqueWorkName}.
    229      *             {@code APPEND} will create a new sequence of work if there is no
    230      *             existing work with {@code uniqueWorkName}; otherwise, {@code work} will be added
    231      *             as a child of all leaf nodes labelled with {@code uniqueWorkName}.
    232      * @return A {@link WorkContinuation} that allows further chaining
    233      */
    234     public abstract WorkContinuation beginUniqueWork(
    235             @NonNull String uniqueWorkName,
    236             @NonNull ExistingWorkPolicy existingWorkPolicy,
    237             @NonNull List<OneTimeWorkRequest> work);
    238 
    239     /**
    240      * This method allows you to enqueue a uniquely-named {@link PeriodicWorkRequest}, where only
    241      * one PeriodicWorkRequest of a particular name can be active at a time.  For example, you may
    242      * only want one sync operation to be active.  If there is one pending, you can choose to let it
    243      * run or replace it with your new work.
    244      *
    245      * The {@code uniqueWorkName} uniquely identifies this PeriodicWorkRequest.
    246      *
    247      * @param uniqueWorkName A unique name which for this operation
    248      * @param existingPeriodicWorkPolicy An {@link ExistingPeriodicWorkPolicy}
    249      * @param periodicWork A {@link PeriodicWorkRequest} to enqueue. {@code REPLACE} ensures that if
    250      *                     there is pending work labelled with {@code uniqueWorkName}, it will be
    251      *                     cancelled and the new work will run. {@code KEEP} will run the new
    252      *                     PeriodicWorkRequest only if there is no pending work labelled with
    253      *                     {@code uniqueWorkName}.
    254      */
    255     public abstract void enqueueUniquePeriodicWork(
    256             @NonNull String uniqueWorkName,
    257             @NonNull ExistingPeriodicWorkPolicy existingPeriodicWorkPolicy,
    258             @NonNull PeriodicWorkRequest periodicWork);
    259 
    260     /**
    261      * Cancels work with the given id if it isn't finished.  Note that cancellation is a best-effort
    262      * policy and work that is already executing may continue to run.
    263      *
    264      * @param id The id of the work
    265      */
    266     public abstract void cancelWorkById(@NonNull UUID id);
    267 
    268     /**
    269      * Cancels all unfinished work with the given tag.  Note that cancellation is a best-effort
    270      * policy and work that is already executing may continue to run.
    271      *
    272      * @param tag The tag used to identify the work
    273      */
    274     public abstract void cancelAllWorkByTag(@NonNull String tag);
    275 
    276     /**
    277      * Cancels all unfinished work in the work chain with the given name.  Note that cancellation is
    278      * a best-effort policy and work that is already executing may continue to run.
    279      *
    280      * @param uniqueWorkName The unique name used to identify the chain of work
    281      */
    282     public abstract void cancelUniqueWork(@NonNull String uniqueWorkName);
    283 
    284     /**
    285      * Cancels all unfinished work.  <b>Use this method with extreme caution!</b>  By invoking it,
    286      * you will potentially affect other modules or libraries in your codebase.  It is strongly
    287      * recommended that you use one of the other cancellation methods at your disposal.
    288      */
    289     public abstract void cancelAllWork();
    290 
    291     /**
    292      * Prunes all eligible finished work from the internal database.  Eligible work must be finished
    293      * ({@link State#SUCCEEDED}, {@link State#FAILED}, or {@link State#CANCELLED}), with zero
    294      * unfinished dependents.
    295      * <p>
    296      * <b>Use this method with caution</b>; by invoking it, you (and any modules and libraries in
    297      * your codebase) will no longer be able to observe the {@link WorkStatus} of the pruned work.
    298      * You do not normally need to call this method - WorkManager takes care to auto-prune its work
    299      * after a sane period of time.  This method also ignores the
    300      * {@link OneTimeWorkRequest.Builder#keepResultsForAtLeast(long, TimeUnit)} policy.
    301      */
    302     public abstract void pruneWork();
    303 
    304     /**
    305      * Gets a {@link LiveData} of the last time all work was cancelled.  This method is intended for
    306      * use by library and module developers who have dependent data in their own repository that
    307      * must be updated or deleted in case someone cancels their work without their prior knowledge.
    308      *
    309      * @return A {@link LiveData} of the timestamp in milliseconds when method that cancelled all
    310      *         work was last invoked
    311      */
    312     public abstract LiveData<Long> getLastCancelAllTimeMillis();
    313 
    314     /**
    315      * Gets a {@link LiveData} of the {@link WorkStatus} for a given work id.
    316      *
    317      * @param id The id of the work
    318      * @return A {@link LiveData} of the {@link WorkStatus} associated with {@code id}
    319      */
    320     public abstract LiveData<WorkStatus> getStatusById(@NonNull UUID id);
    321 
    322     /**
    323      * Gets a {@link LiveData} of the {@link WorkStatus} for all work for a given tag.
    324      *
    325      * @param tag The tag of the work
    326      * @return A {@link LiveData} list of {@link WorkStatus} for work tagged with {@code tag}
    327      */
    328     public abstract LiveData<List<WorkStatus>> getStatusesByTag(@NonNull String tag);
    329 
    330     /**
    331      * Gets a {@link LiveData} of the {@link WorkStatus} for all work in a work chain with a given
    332      * unique name.
    333      *
    334      * @param uniqueWorkName The unique name used to identify the chain of work
    335      * @return A {@link LiveData} of the {@link WorkStatus} for work in the chain named
    336      *         {@code uniqueWorkName}
    337      */
    338     public abstract LiveData<List<WorkStatus>> getStatusesForUniqueWork(
    339             @NonNull String uniqueWorkName);
    340 
    341     /**
    342      * Gets an object that gives access to synchronous methods.
    343      *
    344      * @return A {@link SynchronousWorkManager} object, which gives access to synchronous methods
    345      */
    346     public abstract SynchronousWorkManager synchronous();
    347 
    348     /**
    349      * @hide
    350      */
    351     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    352     protected WorkManager() {
    353     }
    354 }
    355