Problems that aroused, since the “Oreo released” –
Whenever we developers needed to execute a long-running operation in the background, we would choose one of the following options :
a) ThreadPools
b) RxJava / Coroutines
c) ForegroundService
d) JobScheduler
e) Alarm Manager + Broadcast receivers
Above options are helpful but sometimes put us in certain situations to write boilerplate code, that should have been handled by the “API / Library itself” (Network Connectivity / Battery Optimization / Memory Availability issues).
Android being a Linux based system it has its own processes to handle like –
a) Scheduling Tasks
b) Memory Management
c) Process Management & so on
As these processes executes, there might come a case where “Android System” may kill / interrupt/ Suspend our Android background thread / background services
Since the release of Oreo , Android has been more focused on battery optimization, memory optimization, user experience. This Restricts developer to perform, background tasks to run only when the application is in foreground or as a foreground service, if in background.
Which some how degrades user experience !
WorkManager For Rescue !
As from the stable release on March 05, 2019 Developers have started using WorkManager features, Soon Developers have come to know what all things can be accomplished without affecting Oreo’s background restrictions on Apps.
WorkManager is intended for tasks that are Deferrable,
i.e not required to run immediately and required to run reliably even for following :
a) App exits
b) Device restarts
c) Network Connectivity Errors
d) Stopped by system (Where we can provide return retry status for the work being processed )
It is an expansion for JobScheduler framework API.
It also lets you observe the state of the work request so that you can update your UI using LiveData.
It also handles Compatibility with different OS versions.
For example, to ensure compatibility back to API level 14, It chooses an appropriate way to schedule a background task depending on the device API level. it might use JobScheduler or a combination of BroadcastReceiver and AlarmManager.
Lets Code –
What you’ll learn –
1) Adding WorkManager to your project
2) Adding Work constraints to WorkRequests
3) Scheduling WorkRequest
4) Chaining Multiple WorkRequests
There are a few key WorkManager classes we need to know about –
Worker : Actual work we want to perform in the background.
We need to extend this class and override its doWork() method.
WorkRequest : An actual request object with some work (Worker Object).
We would pass our Worker object, required for creation of our
WorkRequest. While creating “WorkRequest” we can specify things
like Constraints on which the Worker will be running with.
Constraints : A constraints specifies the requirements that need to be met before
WorkRequest be executed. These constraints can be related to
network, battery or storage:
Steps to perform background processing by workManager –
1) Add Dependency
2) Create Worker
3) Set desired Constraints to Worker
4) Is Request Periodic ? if yes –> “PeriodicWorkRequest”
if no –> “OnetimeRequest”, WorkManager Classes.
5) Finally, Schedule it via “WorkManager”.
Adding WorkManager dependency –
implementation "android.arch.work:work-runtime:2.2.0" // Current Stable Version
Create a MyWorker class by extending Worker Class –
class MyWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { override fun doWork(): Result { // Define here your work to perform such as // Upload images / log files / Rrefresh App config's data periodically // Return Result.success() , Result.retry() , Result.failure() return Result.success() } }
Creating Work Request –
// Creating Desired Constraints // Should run only when device is in charging mode // should run only connected to network val constraints: Constraints = Constraints.Builder() .setRequiresCharging(true) .setRequiredNetworkType(NetworkType.CONNECTED) .build() // We can also pass params using WorkerManager's Data Class val data = Data.Builder() data.putString("SyncMaster", syncModuleName) /** if work is periodic (Mostly used for Oreo onward devices due to restriction on background services) */ var periodicWorkRequest: PeriodicWorkRequest = PeriodicWorkRequest .Builder(MyWorker::class.java,Duration.ofHours(1)) .setInputData(data.build()) .setConstraints(constraints) .build() /** Else if work is one time task */ var oneTimeWorkRequest : OneTimeWorkRequest = OneTimeWorkRequest .Builder(MyWorker::class.java) .setInputData(data.build()) .setConstraints(constraints) .build() /** As we have applied the same constraints, both request will work only when device is charging or network is connected */
Scheduling Work –
/** Creating a WorkManager object. Request can periodicWorkRequest or oneTimeWorkRequest */ WorkManager mWorkManager = WorkManager.getInstance(Context); mWorkManager.enqueue(request);
Chaining Work –
/** Using same WorkManager instance if we need requests to be executed in synchronous fashion, Which can be perform using */ mWorkManager.beginWith(request1) .then(request2) .then(request3) .then(request4) .enqueue(); // Requests should be unique either // PeriodicWorkRequest or OneTimeWorkRequest
WorkManager guarantees to schedule requests in a Synchronized manner as specified.
WorkManager will Handle The Rest !!!!!