Workmanager
https://developer.android.com/topic/libraries/architecture/workmanager
https://developer.android.com/develop/background-work/background-tasks/persistent
https://developer.android.com/topic/libraries/architecture/workmanager
https://developer.android.com/develop/background-work/background-tasks/persistent
Work manager is a part of jetpack
WorkManager is the recommended solution for persistent work. Work is persistent when it remains scheduled through app restarts and system reboots
Immediate: Tasks that must begin immediately and complete soon. May be expedited.
Long Running: Tasks which might run for longer, potentially longer than 10 minutes.
Deferrable: Scheduled tasks that start at a later time and can run periodically.
In addition to providing a simpler and more consistent API, WorkManager has a number of other key benefits:
Declaratively define the optimal conditions for your work to run using work constraints. For example, run only when the device is on an unmetered network, when the device is idle, or when it has sufficient battery.
WorkManager allows you to schedule work to run one-time or repeatedly using flexible scheduling windows. Work can be tagged and named as well, allowing you to schedule unique, replaceable work and monitor or cancel groups of work together.
Scheduled work is stored in an internally managed SQLite database and WorkManager takes care of ensuring that this work persists and is rescheduled across device reboots.
You can use WorkManager to schedule immediate work for execution in the background. You should use Expedited work for tasks that are important to the user and which complete within a few minutes.
A potential use case for expedited work might be within a chat app when the user wants to send a message or an attached image. Similarly, an app that handles a payment or subscription flow might also want to use expedited work. This is because those tasks are important to the user, execute quickly in the background, need to begin immediately, and should continue to execute even if the user closes the app
Sometimes work fails. WorkManager offers flexible retry policies, including a configurable exponential backoff policy.
For complex related work, chain individual work tasks together using an intuitive interface that allows you to control which pieces run sequentially and which run in parallel.
WorkManager.getInstance(context)
.beginUniqueWork(
OneTimeWorkRequest.from(DownloadImageWorker::class.java)
).then(OneTimeWorkRequest.from(saveImageWorker::class.java))
.then(OneTimeWorkRequest.from(CompressImageWorker::class.java))
.then(OneTimeWorkRequest.from(UploadImageWorkder::class.java))
For each work task, you can define input and output data for that work. When chaining work together, WorkManager automatically passes output data from one work task to the next.
WorkManager integrates seamlessly with Coroutines and RxJava and provides the flexibility to plug in your own asynchronous APIs.
Note: While Coroutines and WorkManager are recommended for different use cases, they are not mutually exclusive. You may use coroutines within work scheduled through WorkManager.
Coroutines are the standard means of leaving the main thread in Kotlin. However, they leave memory once the app closes. For persistent work, use WorkManager.
Once you’ve added the dependencies and synchronized your Gradle project, the next step is to define some work to run.
Work is defined using the Worker class. The doWork() method runs asynchronously on a background thread provided by WorkManager.
To create some work for WorkManager to run, extend the Worker class and override the doWork() method. For example, to create a Worker that uploads images, you can do the following:
The Result returned from doWork() informs the WorkManager service whether the work succeeded and, in the case of failure, whether or not the work should be retried.
Result.success(): The work finished successfully.
Result.failure(): The work failed.
Result.retry(): The work failed and should be tried at another time according to its retry policy.
Once your work is defined, it must be scheduled with the WorkManager service in order to run. WorkManager offers a lot of flexibility in how you schedule your work
However you choose to schedule the work, you will always use a WorkRequest. While a Worker defines the unit of work, a WorkRequest (and its subclasses) define how and when it should be run. In the simplest case, you can use a OneTimeWorkRequest, as shown in the following example.
The getting started guide covered how to create a simple WorkRequest and enqueue it.
In this guide you will learn how to define and customize WorkRequest objects to handle common use cases, such as how to:
Schedule one-time and recurring work
Set work constraints like requiring Wi-Fi or charging
Guarantee a minimum delay in work execution
Set retry and back-off strategies
Pass input data to work
Group related work together using tags
The WorkRequest object contains all of the information needed by WorkManager to schedule and run your work. It includes constraints which must be met for your work to run, scheduling information such as delays or repeating intervals, retry configuration, and may include input data if your work relies on it.
Work is defined in WorkManager via a WorkRequest. In order to schedule any work with WorkManager you must first create a WorkRequest object and then enqueue it.
WorkRequest itself is an abstract base class. There are two derived implementations of this class that you can use to create the request, OneTimeWorkRequest and PeriodicWorkRequest.
For simple work, which requires no additional configuration, use the static method from:
val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)
For more complex work, you can use a builder:
val uploadWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<MyWork>()
// Additional configuration
.build()
This allows WorkManager to execute important work while giving the system better control over access to resources.your app can call setExpedited() to declare that a WorkRequest should run as quickly as possible using an expedited job. The following code snippet provides an example of how to use setExpedited():
val request = OneTimeWorkRequestBuilder<SyncWorker>()
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
WorkManager.getInstance(context)
.enqueue(request)
In this example, we initialize an instance of OneTimeWorkRequest and call setExpedited() on it. This request then becomes expedited work. If the quota allows, it will begin to run immediately in the background.
Your app may at times require that certain work runs periodically. For example, you may want to periodically backup your data, download fresh content in your app, or upload logs to a server.
Here is how you use the PeriodicWorkRequest to create a WorkRequest object which executes periodically:
val saveRequest =
PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS)
// Additional configuration
.build()
To define periodic work with a flex period, you pass a flexInterval along with the repeatInterval when creating the PeriodicWorkRequest. The flex period begins at repeatInterval - flexInterval, and goes to the end of the interval.
val myUploadWork = PeriodicWorkRequestBuilder<SaveImageToFileWorker>(
1, TimeUnit.HOURS, // repeatInterval (the period cycle)
15, TimeUnit.MINUTES) // flexInterval
.build()
Workers don't know whether the work they're doing is expedited or not. But workers can display a notification on some versions of Android when a WorkRequest has been expedited.
as we discussed earlier
If you use a CoroutineWorker, you must implement getForegroundInfo(). You then pass it to setForeground() within doWork(). Doing so will create the notification in versions of Android prior to 12.
class ExpeditedWorker(appContext: Context, workerParams: WorkerParameters):
CoroutineWorker(appContext, workerParams) {
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
NOTIFICATION_ID, createNotification()
)
}
override suspend fun doWork(): Result {
TODO()
}
private fun createNotification() : Notification {
TODO()
}
}
Constraints ensure that work is deferred until optimal conditions are met. The following constraints are available to WorkManager.
To create a set of constraints and associate it with some work, create a Constraints instance using the Contraints.Builder() and assign it to your WorkRequest.Builder().
For example, the following code builds a work request which only runs when the user’s device is both charging and on Wi-Fi: