Concurrency on Android implies running heavy tasks on a separate thread (as opposed to the main thread) to make a user’s experience of your app better.
Background tasks are different from other conversations about concurrency. Some applications may require certain tasks to be run when the app is running in the background or not running (some of these tasks include downloading updates or syncing data with the one on the server). Solutions like Alarm Manager
+ Broadcast receivers
, JobSchedulers
, and Firebase JobDispatcher
already exist and have their own unique use cases. In this article, I will try to explain WorkManager, which is part of Android Jetpack. In my opinion, it is an easier solution.
As mentioned earlier, there are APIs for doing background work. However, using these APIs incorrectly can have a negative effect on our user’s battery and cause them to, eventually, uninstall our app. To help with this problem, Android introduced battery-saving features (i.e., battery saver and doze mode) to properly manage the power usage of apps.
For developers, this solution has introduced more problems because we would need to work with the APIs that do background work and the battery saving features while trying to maintain backward compatibility in the apps we are building. Our code could become very complex which could be a problem in a few months when a new team member tries to go through the codebase. Thankfully, WorkManager came to save the day.
WorkManager provides a generic solution for background work by automatically taking battery and API levels into consideration for us. Other important things to note about WorkManager are:
With WorkManager, you might also choose to run tasks under certain constraints. For example, you might want a particular task to run when the device is idle, charging, and there is internet connectivity.
“Must it run now?” Deferrable work is a task that can be run later and still be useful. For example, fetching data from the server so that a user gets fresh content the next time they open the app is deferrable work. However, sending an instant message is not deferrable work because the message has to be sent immediately.
Guaranteed work is work that runs even if the android device is restarted.
When creating battery-friendly background tasks, there are three things that should ultimately be considered.
To use the WorkManager API, define your Worker
class, implement Worker
, and write the code for the task in the doWork()
function.
class FetchWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params){override fun doWork(): Result{val res = fetchAllData() // the actualt work to be doneif(res){return Result.success()}else{return Result.failure()}}}
To do this work, we need to build a WorkRequest. This helps us to configure when and how our tasks should be run. When doing this, we can also add some constraints like this:
val constraints = Constraints.Builder() //if you want to add constraints.setRequiredNetworkType(NetworkType.CONNECTED).setRequiresDeviceIdle(true).setRequiresCharging(true).build()// create a OneTimeWorkRequest that uses the constraints we just built// OneTimeWorkRequestBuilder is used for non-repeating workval fetchDataRequest = OneTimeWorkRequestBuilder<FetchWorker>().setConstraints(constraints).build()
After creating the WorkRequest, the final step would be to enqueue the request like this:
WorkManager.getInstance().enqueue(fetchDataRequest)
That’s all we need to do. Now, we can be certain that the task will be performed in the future when all three specified constraints are met.
For further reading about the WorkManager API, you can go to the android documentation.