WorkManager in Android Application
Mobile Apps Development A-Z Guide.
Give us a message if you’re interested in Blockchain and FinTech software development or just say Hi at Pharos Production Inc.
Or follow us on Youtube to know more about Software Architecture, Distributed Systems, Blockchain, High-load Systems, Microservices, and Enterprise Design Patterns.
WorkManager was announced on Google I/O 2018. This library is included in the JetPack library set and is designed to perform background tasks. On March 5, 2019, the first stable version of this library was released.
Main features:
- Android support from version 4.0 (API 14 and up).
- Guaranteed execution of tasks, even when restarting the application or the device itself.
- Support asynchronous one-time and regular tasks.
- Setting restrictions (network connection, battery charge) for running tasks.
- Support related tasks with input and output.
So let’s get started:
Step 1. Add WorkManager to Android project
Create a new android project and add a dependency in the grad file.
dependencies {
def work_version = 1.0.0
// Kotlin + coroutines
implementation "android.arch.work:work-runtime-tx:$work_version"
}
Step 2. Create a background task.
To describe the task, it is necessary to expand the class Worker and override the doWork() method, it is run synchronously on a background thread provided by WorkManager:
class WorkerA(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters) {
override fun doWork(): Result {
// Do work here
Thread.sleep(1000)
Log.d(AppConstants.TAG.key, "in A request")
// Return Result
return Result.success()
}
}
The result returned by the doWork method can have the following values:
- Result.success() - finished successfully.
- Result.failure() - failed.
- Result.retry() - needs to be retried at a later time.
Step 3. Configure how and when to run the task.
It is possible to create 2 types of tasks — one-off and periodic.
fun startOneTimeWork() {
val aRequest = OneTimeWorkRequestBuilder<WorkerA>().build()
mWorkManager.enqueue(aRequest)
}fun startPeriodicWork() {
val aRequestPeriodic =
PeriodicWorkRequestBuilder<WorkerA>(1, TimeUnit.DAYS).build()
mWorkManager.enqueueUniquePeriodicWork("Periodic", ExistingPeriodicWorkPolicy.REPLACE, aRequestPeriodic)
}
Periodic work has a minimum interval of 15 minutes and it cannot have an initial delay. Additional information is here.
Step 4. Configure how and when to run the task.
According to the MVVM architecture, actions for launching tasks should take place in the ViewModel. Thus, we need to get a copy of WorkManager and use it to start the task.
class MainActivityViewModel : ViewModel() {
// Variables
private val mWorkManager = WorkManager.getInstance() // Public fun startOneTimeWork() {
val aRequest = OneTimeWorkRequestBuilder<WorkerA>().build()
mWorkManager.enqueue(aRequest)
}
Advanced WorkManager topics.
- Chained sequences of tasks that run in a specified order :
It is also possible to run several tasks sequentially one after another and transfer the results of the work performed to the following tasks.
In the doWork method, which returns Result, it allows you to pass on a given instance of the Data type. This data will be transferred to the constructor of the next worker and will be available.
class WorkerA(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters) {
override fun doWork(): Result {
// Do work here
Thread.sleep(1000)
Log.d(AppConstants.TAG.key, "in A request") val data = Data.Builder().putString(AppConstants.WORKER_A_RESULT.key, "Result WorkerA success").build()
// Return Result
return Result.success(data)
}
In this example, when you start VorkerA first and then transfer its results to the result, WorkerB obtains these results by referring to the inputData variable.
class WorkerB(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters) {
override fun doWork(): Result {
// Do our work
Thread.sleep(2000)
val resultFromA = inputData.getString(AppConstants.WORKER_A_RESULT.key)
Log.d(AppConstants.TAG.key, "results - $resultFromA")
return Result.success()
}
}
If at least one of the tasks is not performed, then the entire chain is canceled. The start of the task chain is performed as follows:
fun startChainingWork() {
val aRequest = OneTimeWorkRequest.Builder(WorkerA::class.java).build()
var continuation = mWorkManager.beginWith(aRequest)
val bRequest = OneTimeWorkRequest.Builder(WorkerB::class.java).build()
continuation = continuation.then(bRequest)
continuation.enqueue()
}
mWorkManager.beginWith() returns WorkContinuation object which allows adding new tasks to the chain;
An example of code you can find on the link below:
Thanks for reading!