blob: 70a8653b68e9d1a759f0fe2e18c8c5335cfb27ef [file] [edit]
/*
* 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 androidx.annotation.WorkerThread
import androidx.concurrent.futures.CallbackToFutureAdapter
import com.google.common.util.concurrent.ListenableFuture
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicBoolean
/**
* A class that performs work synchronously on a background thread provided by [WorkManager].
*
* Worker classes are instantiated at runtime by WorkManager and the [.doWork] method is called on a
* pre-specified background thread (see [Configuration.executor]). This method is for
* **synchronous** processing of your work, meaning that once you return from that method, the
* Worker is considered to be finished and will be destroyed. If you need to do your work
* asynchronously or call asynchronous APIs, you should use [ListenableWorker].
*
* In case the work is preempted for any reason, the same instance of Worker is not reused. This
* means that [.doWork] is called exactly once per Worker instance. A new Worker is created if a
* unit of work needs to be rerun.
*
* A Worker is given a maximum of ten minutes to finish its execution and return a
* [androidx.work.ListenableWorker.Result]. After this time has expired, the Worker will be
* signalled to stop.
*/
public abstract class Worker(context: Context, workerParams: WorkerParameters) :
ListenableWorker(context, workerParams) {
/**
* Override this method to do your actual background processing. This method is called on a
* background thread - you are required to **synchronously** do your work and return the
* [androidx.work.ListenableWorker.Result] from this method. Once you return from this method,
* the Worker is considered to have finished what its doing and will be destroyed. If you need
* to do your work asynchronously on a thread of your own choice, see [ListenableWorker].
*
* A Worker has a well defined
* [execution window](https://d.android.com/reference/android/app/job/JobScheduler) to finish
* its execution and return a [androidx.work.ListenableWorker.Result]. After this time has
* expired, the Worker will be signalled to stop.
*
* @return The [androidx.work.ListenableWorker.Result] of the computation; note that dependent
* work will not execute if you use [androidx.work.ListenableWorker.Result.failure] or
* [androidx.work.ListenableWorker.Result.failure]
*/
@WorkerThread public abstract fun doWork(): Result
final override fun startWork(): ListenableFuture<Result> =
backgroundExecutor.future { doWork() }
override fun getForegroundInfoAsync(): ListenableFuture<ForegroundInfo> =
backgroundExecutor.future { getForegroundInfo() }
/**
* 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 [android.app.NotificationManager].
*
* Starting in Android S and above, WorkManager manages this WorkRequest using an immediate job.
*
* @return A [ForegroundInfo] instance if the WorkRequest is marked immediate. For more
* information look at [WorkRequest.Builder.setExpedited].
* @throws IllegalStateException if it is not overridden and worker tries to go to foreground
*/
@WorkerThread
public open fun getForegroundInfo(): ForegroundInfo {
throw IllegalStateException(
"Expedited WorkRequests require a Worker to provide an implementation for " +
"`getForegroundInfo()`"
)
}
}
private fun <T> Executor.future(block: () -> T): ListenableFuture<T> =
CallbackToFutureAdapter.getFuture {
val cancelled = AtomicBoolean(false)
it.addCancellationListener({ cancelled.set(true) }, DirectExecutor.INSTANCE)
execute {
if (cancelled.get()) return@execute
try {
it.set(block())
} catch (t: Throwable) {
it.setException(t)
}
}
}