WorkManager

The WorkManager library was born to perform background processing (outside MainThread) of applications that the user is not interacting with, dealing with the restrictions imposed on background processing by Android and integrating and simplifying some existing solutions.

Remember that an app is considered to be running in the background as long as each of the following conditions are satisfied:
  • None of the app's activities are currently visible to the user.
  • The app isn't running any foreground services that started while an activity from the app was visible to the user.

Restrictions


Doze mode

If a user leaves a device unplugged and stationary for a period of time, with the screen off, the device enters Doze mode. This mode prevents apps from accessing the network and defers their jobs, syncs, and standard alarms. It, therefore, restricts the use of background services, which can only use these resources in a short period of time called the maintenance window.

Android Oreo

Whenever an app runs in the background, it consumes some of the device's limited resources, like RAM. This can result in an impaired user experience, especially if the user is using a resource-intensive app, such as playing a game or watching video. To improve the user experience, Android 8.0 (API level 26) imposes limitations on what apps can do while running in the background (while users aren't directly interacting with them). Apps are restricted in two ways:
  • Background Service Limitations: While an app is idle, there are limits to its use of background services. This does not apply to foreground services, which are more noticeable to the user.
  • Broadcast Limitations: With limited exceptions, apps cannot use their manifest to register for implicit broadcasts. They can still register for these broadcasts at runtime, and they can use the manifest to register for explicit broadcasts targeted specifically at their app.

When an app goes into the background, it has a window of several minutes in which it is still allowed to create and use services. At the end of that window, the app is considered to be idle. At this time, the system stops the app's background services, just as if the app had called the services' Service.stopSelf() methods.

Note that foreground services aren't restricted, but we need a special attention in the way we create our foreground services. Prior to Android 8.0, the usual way to create a foreground service was to create a background service, then promote that service to the foreground. With Android 8.0, there is a complication; the system doesn't allow a background app to create a background service. For this reason, Android 8.0 introduces the new method startForegroundService() to start a new service in the foreground. After the system has created the service, the app has five seconds to call the service's startForeground() method to show the new service's user-visible notification. If the app does not call startForeground() within the time limit, the system stops the service and declares the app to be ANR (Application Not Responding).

Existing Solutions

The WorkManager API is a suitable and recommended replacement for all previous Android background scheduling APIs, including FirebaseJobDispatcher, GcmNetworkManager, Job Scheduler and Service. WorkManager incorporates the features of its predecessors in a modern, consistent API that works back to API level 14 while also being conscious of battery life. 

Under the hood WorkManager uses an underlying job dispatching service based on the following criteria:



The WorkManager library's components


Worker

Implements a work (a processing to be run in the background). The class must be extended and processing is defined in the doWork() method, executed synchronously (not asynchronously as described incorrectly in official documentation) on a background thread provided by WorkManager.  If you need to do your work asynchronously or call asynchronous APIs, see ListenableWorker.

WorkRequest

The base class for specifying parameters for work's run. The parameters specify if work is one-time or periodic and also can include additional information, such as the constraints under which the work should run, input to the work, a backoff delay, and backoff policy for retrying work.

Constraints

A specification of the requirements that need to be met before a WorkRequest can run. By default, WorkRequest do not have any requirements and can run immediately. By adding requirements, you can make sure that work only runs in certain situations - for example, when device are charging or the storage isn't low.

Backoff delay

Specifies the minimum amount of time to wait before retrying your work after the first attempt. This value can be no less than 10 seconds (or MIN_BACKOFF_MILLIS).

Backoff policy 

Defines how the backoff delay should increase over time for subsequent retry attempts. WorkManager supports 2 backoff policies, LINEAR and EXPONENTIAL.

WorkManager

Receives a WorkRequest and enqueue it. The exact time that the worker is going to be executed depends on the constraints that are used in your WorkRequest and on system optimizations. WorkManager is designed to give the best behavior under these restrictions.

Result

The return of Worker.doWork() method. Represents what happened in your background work.

Basic WorkManager's Implementation


1) Define your work:
class UploadWorker(appContext: Context, workerParams: WorkerParameters):
Worker(appContext, workerParams) {
override fun doWork(): Result {

// Do the work here--in this case, upload the images.
uploadImages()

// Indicate whether the work finished successfully with the Result
return Result.success()
}
}

2) Create a WorkRequest:

val uploadWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<UploadWorker>()
.build()

3) Submit your WorkRequest to WorkManager using the enqueue() method:

WorkManager
    .getInstance(myContext)
    .enqueue(uploadWorkRequest)