java.lang.Object
↳androidx.work.ListenableWorker
Subclasses:
WorkManagerScheduler.SchedulerWorker, RxWorker, Worker, RemoteListenableWorker, DiagnosticsWorker, CombineContinuationsWorker, ConstraintTrackingWorker, RxWorker
Gradle dependencies
compile group: 'androidx.work', name: 'work-runtime', version: '2.8.0-alpha02'
- groupId: androidx.work
- artifactId: work-runtime
- version: 2.8.0-alpha02
Artifact androidx.work:work-runtime:2.8.0-alpha02 it located at Google repository (https://maven.google.com/)
Overview
A class that can perform work asynchronously in WorkManager. For most cases, we
recommend using Worker, which offers a simple synchronous API that is executed on a
pre-specified background thread.
ListenableWorker classes are instantiated at runtime by the WorkerFactory specified in
the Configuration. The ListenableWorker.startWork() method is called on the main thread.
In case the work is preempted and later restarted for any reason, a new instance of
ListenableWorker is created. This means that startWork is called exactly once per
ListenableWorker instance. A new ListenableWorker is created if a unit of work needs to be
rerun.
A ListenableWorker is given a maximum of ten minutes to finish its execution and return a
ListenableWorker.Result. After this time has expired, the worker will be signalled to stop and its
will be cancelled.
Exercise caution when renaming or removing
ListenableWorkers from your codebase.
Summary
Methods |
---|
public final Context | getApplicationContext()
Gets the application . |
public java.util.concurrent.Executor | getBackgroundExecutor()
|
public <any> | getForegroundInfoAsync()
Return an instance of ForegroundInfo if the WorkRequest is important to
the user. |
public final java.util.UUID | getId()
Gets the ID of the WorkRequest that created this Worker. |
public final Data | getInputData()
Gets the input data. |
public final Network | getNetwork()
Gets the to use for this Worker. |
public final int | getRunAttemptCount()
Gets the current run attempt count for this work. |
public final java.util.Set<java.lang.String> | getTags()
Gets a java.util.Set of tags associated with this Worker's WorkRequest. |
public TaskExecutor | getTaskExecutor()
|
public final java.util.List<java.lang.String> | getTriggeredContentAuthorities()
Gets the list of content authorities that caused this Worker to execute. |
public final java.util.List<Uri> | getTriggeredContentUris()
Gets the list of content s that caused this Worker to execute. |
public WorkerFactory | getWorkerFactory()
|
public final boolean | isStopped()
Returns true if this Worker has been told to stop. |
public final boolean | isUsed()
|
public void | onStopped()
This method is invoked when this Worker has been told to stop. |
public final <any> | setForegroundAsync(ForegroundInfo foregroundInfo)
This specifies that the WorkRequest is long-running or otherwise important. |
public <any> | setProgressAsync(Data data)
Updates ListenableWorker progress. |
public final void | setUsed()
Marks this worker as used to make sure we enforce the policy that workers can only be used
once and that WorkerFactories return a new instance each time. |
public abstract <any> | startWork()
Override this method to start your actual background processing. |
public final void | stop()
|
from java.lang.Object | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructors
Parameters:
appContext: The application
workerParams: Parameters to setup the internal state of this worker
Methods
public final Context
getApplicationContext()
Gets the application .
Returns:
The application
public final java.util.UUID
getId()
Gets the ID of the WorkRequest that created this Worker.
Returns:
The ID of the creating WorkRequest
public final
Data getInputData()
Gets the input data. Note that in the case that there are multiple prerequisites for this
Worker, the input data has been run through an InputMerger.
Returns:
The input data for this work
See also: OneTimeWorkRequest.Builder.setInputMerger(Class extends InputMerger>)
public final java.util.Set<java.lang.String>
getTags()
Gets a java.util.Set
of tags associated with this Worker's WorkRequest.
Returns:
The java.util.Set
of tags associated with this Worker's WorkRequest
See also: WorkRequest.Builder.addTag(String)
public final java.util.List<Uri>
getTriggeredContentUris()
Gets the list of content s that caused this Worker to execute. See
JobParameters#getTriggeredContentUris() for relevant JobScheduler code.
Returns:
The list of content s that caused this Worker to execute
See also: Constraints.Builder
public final java.util.List<java.lang.String>
getTriggeredContentAuthorities()
Gets the list of content authorities that caused this Worker to execute. See
JobParameters#getTriggeredContentAuthorities() for relevant JobScheduler
code.
Returns:
The list of content authorities that caused this Worker to execute
public final Network
getNetwork()
Gets the to use for this Worker. This method returns
null if there is no network needed for this work request.
Returns:
The specified by the OS to be used with this Worker
public final int
getRunAttemptCount()
Gets the current run attempt count for this work. Note that for periodic work, this value
gets reset between periods.
Returns:
The current run attempt count for this work.
public abstract <any>
startWork()
Override this method to start your actual background processing. This method is called on
the main thread.
A ListenableWorker has a well defined
execution window
to to finish its execution and return a ListenableWorker.Result. After this time has expired, the
worker will be signalled to stop and its will be cancelled.
The future will also be cancelled if this worker is stopped for any reason
(see ListenableWorker.onStopped()).
Returns:
A ListenableFuture with the ListenableWorker.Result of the computation. If you
cancel this Future, WorkManager will treat this unit of work as failed.
public <any>
setProgressAsync(
Data data)
Updates ListenableWorker progress.
Parameters:
data: The progress Data
Returns:
A which resolves after progress is persisted.
Cancelling this future is a no-op.
This specifies that the WorkRequest is long-running or otherwise important. In
this case, WorkManager provides a signal to the OS that the process should be kept alive
if possible while this work is executing.
Calls to setForegroundAsync *must* complete before a ListenableWorker
signals completion by returning a ListenableWorker.Result.
Under the hood, WorkManager manages and runs a foreground service on your behalf to
execute this WorkRequest, showing the notification provided in
ForegroundInfo.
Calling setForegroundAsync will fail with an
java.lang.IllegalStateException
when the process is subject to foreground
service restrictions. Consider using
WorkRequest.Builder.setExpedited(OutOfQuotaPolicy) and
ListenableWorker.getForegroundInfoAsync() instead.
Parameters:
foregroundInfo: The ForegroundInfo
Returns:
A which resolves after the ListenableWorker
transitions to running in the context of a foreground .
public <any>
getForegroundInfoAsync()
Return an instance of ForegroundInfo if the WorkRequest is important to
the user. In this case, WorkManager provides a signal to the OS that the process should
be kept alive while this work is executing.
Prior to Android S, WorkManager manages and runs a foreground service on your behalf to
execute the WorkRequest, showing the notification provided in the ForegroundInfo.
To update this notification subsequently, the application can use
.
Starting in Android S and above, WorkManager manages this WorkRequest using an immediate job.
Returns:
A of ForegroundInfo instance if the WorkRequest
is marked immediate. For more information look at
WorkRequest.Builder.setExpedited(OutOfQuotaPolicy).
public final boolean
isStopped()
Returns true if this Worker has been told to stop. This could be because of an
explicit cancellation signal by the user, or because the system has decided to preempt the
task. In these cases, the results of the work will be ignored by WorkManager and it is safe
to stop the computation. WorkManager will retry the work at a later time if necessary.
Returns:
true if the work operation has been interrupted
This method is invoked when this Worker has been told to stop. At this point, the
returned by the instance of ListenableWorker.startWork() is
also cancelled. This could happen due to an explicit cancellation signal by the user, or
because the system has decided to preempt the task. In these cases, the results of the
work will be ignored by WorkManager. All processing in this method should be lightweight
- there are no contractual guarantees about which thread will invoke this call, so this
should not be a long-running or blocking operation.
public final boolean
isUsed()
Returns:
true if this worker has already been marked as used
See also: ListenableWorker.setUsed()
public final void
setUsed()
Marks this worker as used to make sure we enforce the policy that workers can only be used
once and that WorkerFactories return a new instance each time.
See also: ListenableWorker.isUsed()
public java.util.concurrent.Executor
getBackgroundExecutor()
Source
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.work;
import android.content.Context;
import android.net.Network;
import android.net.Uri;
import androidx.annotation.IntRange;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.work.impl.utils.futures.SettableFuture;
import androidx.work.impl.utils.taskexecutor.TaskExecutor;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
/**
* A class that can perform work asynchronously in {@link WorkManager}. For most cases, we
* recommend using {@link Worker}, which offers a simple synchronous API that is executed on a
* pre-specified background thread.
* <p>
* ListenableWorker classes are instantiated at runtime by the {@link WorkerFactory} specified in
* the {@link Configuration}. The {@link #startWork()} method is called on the main thread.
* <p>
* In case the work is preempted and later restarted for any reason, a new instance of
* ListenableWorker is created. This means that {@code startWork} is called exactly once per
* ListenableWorker instance. A new ListenableWorker is created if a unit of work needs to be
* rerun.
* <p>
* A ListenableWorker is given a maximum of ten minutes to finish its execution and return a
* {@link Result}. After this time has expired, the worker will be signalled to stop and its
* {@link ListenableFuture} will be cancelled.
* <p>
* Exercise caution when <a href="WorkManager.html#worker_class_names">renaming or removing
* ListenableWorkers</a> from your codebase.
*/
public abstract class ListenableWorker {
private @NonNull Context mAppContext;
private @NonNull WorkerParameters mWorkerParams;
private volatile boolean mStopped;
private boolean mUsed;
/**
* @param appContext The application {@link Context}
* @param workerParams Parameters to setup the internal state of this worker
*/
public ListenableWorker(@NonNull Context appContext, @NonNull WorkerParameters workerParams) {
// Actually make sure we don't get nulls.
if (appContext == null) {
throw new IllegalArgumentException("Application Context is null");
}
if (workerParams == null) {
throw new IllegalArgumentException("WorkerParameters is null");
}
mAppContext = appContext;
mWorkerParams = workerParams;
}
/**
* Gets the application {@link android.content.Context}.
*
* @return The application {@link android.content.Context}
*/
public final @NonNull Context getApplicationContext() {
return mAppContext;
}
/**
* Gets the ID of the {@link WorkRequest} that created this Worker.
*
* @return The ID of the creating {@link WorkRequest}
*/
public final @NonNull UUID getId() {
return mWorkerParams.getId();
}
/**
* Gets the input data. Note that in the case that there are multiple prerequisites for this
* Worker, the input data has been run through an {@link InputMerger}.
*
* @return The input data for this work
* @see OneTimeWorkRequest.Builder#setInputMerger(Class)
*/
public final @NonNull Data getInputData() {
return mWorkerParams.getInputData();
}
/**
* Gets a {@link java.util.Set} of tags associated with this Worker's {@link WorkRequest}.
*
* @return The {@link java.util.Set} of tags associated with this Worker's {@link WorkRequest}
* @see WorkRequest.Builder#addTag(String)
*/
public final @NonNull Set<String> getTags() {
return mWorkerParams.getTags();
}
/**
* Gets the list of content {@link android.net.Uri}s that caused this Worker to execute. See
* {@code JobParameters#getTriggeredContentUris()} for relevant {@code JobScheduler} code.
*
* @return The list of content {@link android.net.Uri}s that caused this Worker to execute
* @see Constraints.Builder#addContentUriTrigger(android.net.Uri, boolean)
*/
@RequiresApi(24)
public final @NonNull List<Uri> getTriggeredContentUris() {
return mWorkerParams.getTriggeredContentUris();
}
/**
* Gets the list of content authorities that caused this Worker to execute. See
* {@code JobParameters#getTriggeredContentAuthorities()} for relevant {@code JobScheduler}
* code.
*
* @return The list of content authorities that caused this Worker to execute
*/
@RequiresApi(24)
public final @NonNull List<String> getTriggeredContentAuthorities() {
return mWorkerParams.getTriggeredContentAuthorities();
}
/**
* Gets the {@link android.net.Network} to use for this Worker. This method returns
* {@code null} if there is no network needed for this work request.
*
* @return The {@link android.net.Network} specified by the OS to be used with this Worker
*/
@RequiresApi(28)
public final @Nullable Network getNetwork() {
return mWorkerParams.getNetwork();
}
/**
* Gets the current run attempt count for this work. Note that for periodic work, this value
* gets reset between periods.
*
* @return The current run attempt count for this work.
*/
@IntRange(from = 0)
public final int getRunAttemptCount() {
return mWorkerParams.getRunAttemptCount();
}
/**
* Override this method to start your actual background processing. This method is called on
* the main thread.
* <p>
* A ListenableWorker has a well defined
* <a href="https://d.android.com/reference/android/app/job/JobScheduler">execution window</a>
* to to finish its execution and return a {@link Result}. After this time has expired, the
* worker will be signalled to stop and its {@link ListenableFuture} will be cancelled.
* <p>
* The future will also be cancelled if this worker is stopped for any reason
* (see {@link #onStopped()}).
*
* @return A {@code ListenableFuture} with the {@link Result} of the computation. If you
* cancel this Future, WorkManager will treat this unit of work as failed.
*/
@MainThread
public abstract @NonNull ListenableFuture<Result> startWork();
/**
* Updates {@link ListenableWorker} progress.
*
* @param data The progress {@link Data}
* @return A {@link ListenableFuture} which resolves after progress is persisted.
* Cancelling this future is a no-op.
*/
@NonNull
public ListenableFuture<Void> setProgressAsync(@NonNull Data data) {
return mWorkerParams.getProgressUpdater()
.updateProgress(getApplicationContext(), getId(), data);
}
/**
* This specifies that the {@link WorkRequest} is long-running or otherwise important. In
* this case, WorkManager provides a signal to the OS that the process should be kept alive
* if possible while this work is executing.
* <p>
* Calls to {@code setForegroundAsync} *must* complete before a {@link ListenableWorker}
* signals completion by returning a {@link Result}.
* <p>
* Under the hood, WorkManager manages and runs a foreground service on your behalf to
* execute this WorkRequest, showing the notification provided in
* {@link ForegroundInfo}.
* <p>
* Calling {@code setForegroundAsync} will fail with an
* {@link IllegalStateException} when the process is subject to foreground
* service restrictions. Consider using
* {@link WorkRequest.Builder#setExpedited(OutOfQuotaPolicy)} and
* {@link ListenableWorker#getForegroundInfoAsync()} instead.
*
* @param foregroundInfo The {@link ForegroundInfo}
* @return A {@link ListenableFuture} which resolves after the {@link ListenableWorker}
* transitions to running in the context of a foreground {@link android.app.Service}.
*/
@NonNull
public final ListenableFuture<Void> setForegroundAsync(@NonNull ForegroundInfo foregroundInfo) {
return mWorkerParams.getForegroundUpdater()
.setForegroundAsync(getApplicationContext(), getId(), foregroundInfo);
}
/**
* Return an instance of {@link ForegroundInfo} if the {@link WorkRequest} is important to
* the user. In this case, WorkManager provides a signal to the OS that the process should
* be kept alive while this work is executing.
* <p>
* Prior to Android S, WorkManager manages and runs a foreground service on your behalf to
* execute the WorkRequest, showing the notification provided in the {@link ForegroundInfo}.
* To update this notification subsequently, the application can use
* {@link android.app.NotificationManager}.
* <p>
* Starting in Android S and above, WorkManager manages this WorkRequest using an immediate job.
*
* @return A {@link ListenableFuture} of {@link ForegroundInfo} instance if the WorkRequest
* is marked immediate. For more information look at
* {@link WorkRequest.Builder#setExpedited(OutOfQuotaPolicy)}.
*/
@NonNull
public ListenableFuture<ForegroundInfo> getForegroundInfoAsync() {
SettableFuture<ForegroundInfo> future = SettableFuture.create();
String message =
"Expedited WorkRequests require a ListenableWorker to provide an implementation for"
+ " `getForegroundInfoAsync()`";
future.setException(new IllegalStateException(message));
return future;
}
/**
* Returns {@code true} if this Worker has been told to stop. This could be because of an
* explicit cancellation signal by the user, or because the system has decided to preempt the
* task. In these cases, the results of the work will be ignored by WorkManager and it is safe
* to stop the computation. WorkManager will retry the work at a later time if necessary.
*
*
* @return {@code true} if the work operation has been interrupted
*/
public final boolean isStopped() {
return mStopped;
}
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public final void stop() {
mStopped = true;
onStopped();
}
/**
* This method is invoked when this Worker has been told to stop. At this point, the
* {@link ListenableFuture} returned by the instance of {@link #startWork()} is
* also cancelled. This could happen due to an explicit cancellation signal by the user, or
* because the system has decided to preempt the task. In these cases, the results of the
* work will be ignored by WorkManager. All processing in this method should be lightweight
* - there are no contractual guarantees about which thread will invoke this call, so this
* should not be a long-running or blocking operation.
*/
public void onStopped() {
// Do nothing by default.
}
/**
* @return {@code true} if this worker has already been marked as used
* @see #setUsed()
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public final boolean isUsed() {
return mUsed;
}
/**
* Marks this worker as used to make sure we enforce the policy that workers can only be used
* once and that WorkerFactories return a new instance each time.
* @see #isUsed()
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public final void setUsed() {
mUsed = true;
}
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public @NonNull Executor getBackgroundExecutor() {
return mWorkerParams.getBackgroundExecutor();
}
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public @NonNull TaskExecutor getTaskExecutor() {
return mWorkerParams.getTaskExecutor();
}
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public @NonNull WorkerFactory getWorkerFactory() {
return mWorkerParams.getWorkerFactory();
}
/**
* The result of a {@link ListenableWorker}'s computation. Call {@link #success()},
* {@link #failure()}, or {@link #retry()} or one of their variants to generate an object
* indicating what happened in your background work.
*/
public abstract static class Result {
/**
* Returns an instance of {@link Result} that can be used to indicate that the work
* completed successfully. Any work that depends on this can be executed as long as all of
* its other dependencies and constraints are met.
*
* @return An instance of {@link Result} indicating successful execution of work
*/
@NonNull
public static Result success() {
return new Success();
}
/**
* Returns an instance of {@link Result} that can be used to indicate that the work
* completed successfully. Any work that depends on this can be executed as long as all of
* its other dependencies and constraints are met.
*
* @param outputData A {@link Data} object that will be merged into the input Data of any
* OneTimeWorkRequest that is dependent on this work
* @return An instance of {@link Result} indicating successful execution of work
*/
@NonNull
public static Result success(@NonNull Data outputData) {
return new Success(outputData);
}
/**
* Returns an instance of {@link Result} that can be used to indicate that the work
* encountered a transient failure and should be retried with backoff specified in
* {@link WorkRequest.Builder#setBackoffCriteria(BackoffPolicy, long, TimeUnit)}.
*
* @return An instance of {@link Result} indicating that the work needs to be retried
*/
@NonNull
public static Result retry() {
return new Retry();
}
/**
* Returns an instance of {@link Result} that can be used to indicate that the work
* completed with a permanent failure. Any work that depends on this will also be marked as
* failed and will not be run. <b>If you need child workers to run, you need to use
* {@link #success()} or {@link #success(Data)}</b>; failure indicates a permanent stoppage
* of the chain of work.
*
* @return An instance of {@link Result} indicating failure when executing work
*/
@NonNull
public static Result failure() {
return new Failure();
}
/**
* Returns an instance of {@link Result} that can be used to indicate that the work
* completed with a permanent failure. Any work that depends on this will also be marked as
* failed and will not be run. <b>If you need child workers to run, you need to use
* {@link #success()} or {@link #success(Data)}</b>; failure indicates a permanent stoppage
* of the chain of work.
*
* @param outputData A {@link Data} object that can be used to keep track of why the work
* failed
* @return An instance of {@link Result} indicating failure when executing work
*/
@NonNull
public static Result failure(@NonNull Data outputData) {
return new Failure(outputData);
}
/**
* @return The output {@link Data} which will be merged into the input {@link Data} of
* any {@link OneTimeWorkRequest} that is dependent on this work request.
*/
@NonNull
public abstract Data getOutputData();
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
Result() {
// Restricting access to the constructor, to give Result a sealed class
// like behavior.
}
/**
* Used to indicate that the work completed successfully. Any work that depends on this
* can be executed as long as all of its other dependencies and constraints are met.
*
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final class Success extends Result {
private final Data mOutputData;
public Success() {
this(Data.EMPTY);
}
/**
* @param outputData A {@link Data} object that will be merged into the input Data of
* any OneTimeWorkRequest that is dependent on this work
*/
public Success(@NonNull Data outputData) {
super();
mOutputData = outputData;
}
@Override
public @NonNull Data getOutputData() {
return mOutputData;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Success success = (Success) o;
return mOutputData.equals(success.mOutputData);
}
@Override
public int hashCode() {
String name = Success.class.getName();
return 31 * name.hashCode() + mOutputData.hashCode();
}
@NonNull
@Override
public String toString() {
return "Success {" + "mOutputData=" + mOutputData + '}';
}
}
/**
* Used to indicate that the work completed with a permanent failure. Any work that depends
* on this will also be marked as failed and will not be run. <b>If you need child workers
* to run, you need to return {@link Result.Success}</b>; failure indicates a permanent
* stoppage of the chain of work.
*
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final class Failure extends Result {
private final Data mOutputData;
public Failure() {
this(Data.EMPTY);
}
/**
* @param outputData A {@link Data} object that can be used to keep track of why the
* work failed
*/
public Failure(@NonNull Data outputData) {
super();
mOutputData = outputData;
}
@Override
public @NonNull Data getOutputData() {
return mOutputData;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Failure failure = (Failure) o;
return mOutputData.equals(failure.mOutputData);
}
@Override
public int hashCode() {
String name = Failure.class.getName();
return 31 * name.hashCode() + mOutputData.hashCode();
}
@NonNull
@Override
public String toString() {
return "Failure {" + "mOutputData=" + mOutputData + '}';
}
}
/**
* Used to indicate that the work encountered a transient failure and should be retried with
* backoff specified in
* {@link WorkRequest.Builder#setBackoffCriteria(BackoffPolicy, long, TimeUnit)}.
*
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static final class Retry extends Result {
public Retry() {
super();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
// We are treating all instances of Retry as equivalent.
return o != null && getClass() == o.getClass();
}
@Override
public int hashCode() {
String name = Retry.class.getName();
return name.hashCode();
}
@NonNull
@Override
public Data getOutputData() {
return Data.EMPTY;
}
@NonNull
@Override
public String toString() {
return "Retry";
}
}
}
}