Worker.java revision 5d373d376edddb57cd822dd06ed54f97ef949586
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
17package androidx.work;
18
19import android.content.Context;
20import android.net.Uri;
21import android.support.annotation.Keep;
22import android.support.annotation.NonNull;
23import android.support.annotation.Nullable;
24import android.support.annotation.RequiresApi;
25import android.support.annotation.RestrictTo;
26import android.support.annotation.WorkerThread;
27
28import androidx.work.impl.Extras;
29
30import java.util.Set;
31import java.util.UUID;
32import java.util.concurrent.TimeUnit;
33
34/**
35 * The basic object that performs work.  Worker classes are instantiated at runtime by
36 * {@link WorkManager} and the {@link #doWork()} method is called on a background thread.  In case
37 * the work is pre-empted for any reason, the same instance of Worker is not reused.  This means
38 * that {@link #doWork()} is called exactly once per Worker instance.
39 */
40public abstract class Worker {
41
42    /**
43     * The result of the Worker's computation that is returned in the {@link #doWork()} method.
44     */
45    public enum WorkerResult {
46        /**
47         * Used to indicate that the work completed successfully.  Any work that depends on this
48         * can be executed as long as all of its other dependencies and constraints are met.
49         */
50        SUCCESS,
51
52        /**
53         * Used to indicate that the work completed with a permanent failure.  Any work that depends
54         * on this will also be marked as failed and will not be run.
55         */
56        FAILURE,
57
58        /**
59         * Used to indicate that the work encountered a transient failure and should be retried with
60         * backoff specified in
61         * {@link WorkRequest.Builder#setBackoffCriteria(BackoffPolicy, long, TimeUnit)}.
62         */
63        RETRY
64    }
65
66    @SuppressWarnings("NullableProblems")   // Set by internalInit
67    private @NonNull Context mAppContext;
68    @SuppressWarnings("NullableProblems")   // Set by internalInit
69    private @NonNull UUID mId;
70    @SuppressWarnings("NullableProblems")   // Set by internalInit
71    private @NonNull Extras mExtras;
72    private @NonNull Data mOutputData = Data.EMPTY;
73    private volatile boolean mStopped;
74    private volatile boolean mCancelled;
75
76    /**
77     * Gets the application {@link Context}.
78     *
79     * @return The application {@link Context}
80     */
81    public final @NonNull Context getApplicationContext() {
82        return mAppContext;
83    }
84
85    /**
86     * Gets the ID of the {@link WorkRequest} that created this Worker.
87     *
88     * @return The ID of the creating {@link WorkRequest}
89     */
90    public final @NonNull UUID getId() {
91        return mId;
92    }
93
94    /**
95     * Gets the input data.  Note that in the case that there are multiple prerequisites for this
96     * Worker, the input data has been run through an {@link InputMerger}.
97     *
98     * @return The input data for this work
99     * @see OneTimeWorkRequest.Builder#setInputMerger(Class)
100     */
101    public final @NonNull Data getInputData() {
102        return mExtras.getInputData();
103    }
104
105    /**
106     * Gets a {@link Set} of tags associated with this Worker's {@link WorkRequest}.
107     *
108     * @return The {@link Set} of tags associated with this Worker's {@link WorkRequest}
109     * @see WorkRequest.Builder#addTag(String)
110     */
111    public final @NonNull Set<String> getTags() {
112        return mExtras.getTags();
113    }
114
115    /**
116     * Gets the array of content {@link Uri}s that caused this Worker to execute
117     *
118     * @return The array of content {@link Uri}s that caused this Worker to execute
119     * @see Constraints.Builder#addContentUriTrigger(Uri, boolean)
120     */
121    @RequiresApi(24)
122    public final @Nullable Uri[] getTriggeredContentUris() {
123        Extras.RuntimeExtras runtimeExtras = mExtras.getRuntimeExtras();
124        return (runtimeExtras == null) ? null : runtimeExtras.triggeredContentUris;
125    }
126
127    /**
128     * Gets the array of content authorities that caused this Worker to execute
129     *
130     * @return The array of content authorities that caused this Worker to execute
131     */
132    @RequiresApi(24)
133    public final @Nullable String[] getTriggeredContentAuthorities() {
134        Extras.RuntimeExtras runtimeExtras = mExtras.getRuntimeExtras();
135        return (runtimeExtras == null) ? null : runtimeExtras.triggeredContentAuthorities;
136    }
137
138    /**
139     * Override this method to do your actual background processing.
140     *
141     * @return The result of the work, corresponding to a {@link WorkerResult} value.  If a
142     * different value is returned, the result shall be defaulted to
143     * {@link Worker.WorkerResult#FAILURE}.
144     */
145    @WorkerThread
146    public abstract @NonNull WorkerResult doWork();
147
148    /**
149     * Call this method to pass an {@link Data} object to {@link Worker} that is
150     * dependent on this one.
151     *
152     * Note that if there are multiple {@link Worker}s that contribute to the target, the
153     * Data will be merged together, so it is up to the developer to make sure that keys are
154     * unique.  New values and types will clobber old values and types, and if there are multiple
155     * parent Workers of a child Worker, the order of clobbering may not be deterministic.
156     *
157     * This method is invoked after {@link #doWork()} returns {@link Worker.WorkerResult#SUCCESS}
158     * and there are chained jobs available.
159     *
160     * For example, if you had this structure:
161     *
162     * {@code WorkManager.getInstance(context)
163     *             .enqueueWithDefaults(WorkerA.class, WorkerB.class)
164     *             .then(WorkerC.class)
165     *             .enqueue()}
166     *
167     * This method would be called for both WorkerA and WorkerB after their successful completion,
168     * modifying the input Data for WorkerC.
169     *
170     * @param outputData An {@link Data} object that will be merged into the input Data of any
171     *                   OneTimeWorkRequest that is dependent on this one, or {@code null} if there
172     *                   is nothing to contribute
173     */
174    public final void setOutputData(@NonNull Data outputData) {
175        mOutputData = outputData;
176    }
177
178    public final @NonNull Data getOutputData() {
179        return mOutputData;
180    }
181
182    /**
183     * Returns {@code true} if this Worker has been told to stop.  This could be because of an
184     * explicit cancellation signal by the user, or because the system has decided to preempt the
185     * task. In these cases, the results of the work will be ignored by WorkManager and it is safe
186     * to stop the computation.
187     *
188     * @return {@code true} if the work operation has been interrupted
189     */
190    public final boolean isStopped() {
191        return mStopped;
192    }
193
194    /**
195     * Returns {@code true} if this Worker has been told to stop and explicitly informed that it is
196     * cancelled and will never execute again.  If {@link #isStopped()} returns {@code true} but
197     * this method returns {@code false}, that means the system has decided to preempt the task.
198     * <p>
199     * Note that it is almost never sufficient to check only this method; its value is only
200     * meaningful when {@link #isStopped()} returns {@code true}.
201     * <p>
202     * @return {@code true} if this work operation has been cancelled
203     */
204    public final boolean isCancelled() {
205        return mCancelled;
206    }
207
208    /**
209     * @hide
210     */
211    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
212    public final void stop(boolean cancelled) {
213        mStopped = true;
214        mCancelled = cancelled;
215        onStopped(cancelled);
216    }
217
218    /**
219     * This method is invoked when this Worker has been told to stop.  This could happen due
220     * to an explicit cancellation signal by the user, or because the system has decided to preempt
221     * the task.  In these cases, the results of the work will be ignored by WorkManager.  All
222     * processing in this method should be lightweight - there are no contractual guarantees about
223     * which thread will invoke this call, so this should not be a long-running or blocking
224     * operation.
225     *
226     * @param cancelled If {@code true}, the work has been explicitly cancelled
227     */
228    public void onStopped(boolean cancelled) {
229        // Do nothing by default.
230    }
231
232    @Keep
233    @SuppressWarnings("unused")
234    private void internalInit(
235            @NonNull Context appContext,
236            @NonNull UUID id,
237            @NonNull Extras extras) {
238        mAppContext = appContext;
239        mId = id;
240        mExtras = extras;
241    }
242
243    /**
244     * @hide
245     */
246    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
247    public @NonNull Extras getExtras() {
248        return mExtras;
249    }
250}
251