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