Worker.java revision eda66d6e6b83e6f68717be95ec10e7ad8f070a83
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 WorkerResult {
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, if any.  If this value is {@code null}, the
141     * Worker may use the default network.
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     * Override this method to do your actual background processing.
153     *
154     * @return The result of the work, corresponding to a {@link WorkerResult} value.  If a
155     * different value is returned, the result shall be defaulted to
156     * {@link Worker.WorkerResult#FAILURE}.
157     */
158    @WorkerThread
159    public abstract @NonNull WorkerResult doWork();
160
161    /**
162     * Call this method to pass an {@link Data} object to {@link Worker} that is
163     * dependent on this one.
164     *
165     * Note that if there are multiple {@link Worker}s that contribute to the target, the
166     * Data will be merged together, so it is up to the developer to make sure that keys are
167     * unique.  New values and types will clobber old values and types, and if there are multiple
168     * parent Workers of a child Worker, the order of clobbering may not be deterministic.
169     *
170     * This method is invoked after {@link #doWork()} returns {@link Worker.WorkerResult#SUCCESS}
171     * and there are chained jobs available.
172     *
173     * For example, if you had this structure:
174     *
175     * {@code WorkManager.getInstance(context)
176     *             .enqueueWithDefaults(WorkerA.class, WorkerB.class)
177     *             .then(WorkerC.class)
178     *             .enqueue()}
179     *
180     * This method would be called for both WorkerA and WorkerB after their successful completion,
181     * modifying the input Data for WorkerC.
182     *
183     * @param outputData An {@link Data} object that will be merged into the input Data of any
184     *                   OneTimeWorkRequest that is dependent on this one, or {@code null} if there
185     *                   is nothing to contribute
186     */
187    public final void setOutputData(@NonNull Data outputData) {
188        mOutputData = outputData;
189    }
190
191    public final @NonNull Data getOutputData() {
192        return mOutputData;
193    }
194
195    /**
196     * Returns {@code true} if this Worker has been told to stop.  This could be because of an
197     * explicit cancellation signal by the user, or because the system has decided to preempt the
198     * task. In these cases, the results of the work will be ignored by WorkManager and it is safe
199     * to stop the computation.
200     *
201     * @return {@code true} if the work operation has been interrupted
202     */
203    public final boolean isStopped() {
204        return mStopped;
205    }
206
207    /**
208     * Returns {@code true} if this Worker has been told to stop and explicitly informed that it is
209     * cancelled and will never execute again.  If {@link #isStopped()} returns {@code true} but
210     * this method returns {@code false}, that means the system has decided to preempt the task.
211     * <p>
212     * Note that it is almost never sufficient to check only this method; its value is only
213     * meaningful when {@link #isStopped()} returns {@code true}.
214     * <p>
215     * @return {@code true} if this work operation has been cancelled
216     */
217    public final boolean isCancelled() {
218        return mCancelled;
219    }
220
221    /**
222     * @hide
223     */
224    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
225    public final void stop(boolean cancelled) {
226        mStopped = true;
227        mCancelled = cancelled;
228        onStopped(cancelled);
229    }
230
231    /**
232     * This method is invoked when this Worker has been told to stop.  This could happen due
233     * to an explicit cancellation signal by the user, or because the system has decided to preempt
234     * the task.  In these cases, the results of the work will be ignored by WorkManager.  All
235     * processing in this method should be lightweight - there are no contractual guarantees about
236     * which thread will invoke this call, so this should not be a long-running or blocking
237     * operation.
238     *
239     * @param cancelled If {@code true}, the work has been explicitly cancelled
240     */
241    public void onStopped(boolean cancelled) {
242        // Do nothing by default.
243    }
244
245    @Keep
246    @SuppressWarnings("unused")
247    private void internalInit(
248            @NonNull Context appContext,
249            @NonNull UUID id,
250            @NonNull Extras extras) {
251        mAppContext = appContext;
252        mId = id;
253        mExtras = extras;
254    }
255
256    /**
257     * @hide
258     */
259    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
260    public @NonNull Extras getExtras() {
261        return mExtras;
262    }
263}
264