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