<p>Google released <a href="https://android-developers.googleblog.com/2018/05/use-android-jetpack-to-accelerate-your.html" data-href="https://android-developers.googleblog.com/2018/05/use-android-jetpack-to-accelerate-your.html"><strong><span style="color: #008000;">Android Jetpack</span></strong></a>. It’s a set of libraries, tools and architectural guidance to help make it quick and easy to build great Android apps. In this Android Jetpack, team at Google release one library specifically designed for scheduling and managing the background tasks. It’s called “<a href="https://developer.android.com/topic/libraries/architecture/workmanager" data-href="https://developer.android.com/topic/libraries/architecture/workmanager"><strong><span style="color: #008000;">WorkManager</span></strong></a>”.</p>
<h4><span style="color: #000080;"><strong>WorkManager</strong></span></h4>
<p>The <strong><span style="color: #008000;">WorkManager</span></strong> API makes it easy to specify deferrable, asynchronous tasks and when they should run. These APIs let you create a task and hand it off to WorkManager to run immediately or at an appropriate time. For example, an app might need to download new resources from the network from time to time. Using these classes, you can set up a task, choose appropriate circumstances for it to run (like &#8220;only while device is charging and online&#8221;), and hand it off to WorkManager to run when the conditions are met. The task is still guaranteed to run, even if your app is force-quit or the device is rebooted.</p>
<h3></h3>
<h4><span style="color: #000080;"><strong>Why need WorkManager</strong></span></h4>
<p>For background task which needs guaranteed execution and can be deferrable we have lot of options to do.We can use <strong><span style="color: #008000;">JobScheduler</span></strong> API but it is supported for API≥23. To overcome this we have <strong><span style="color: #008000;">FirebaseJobDispatcher</span></strong> library which provide backward compatibility upto API 14 but it requires Google Play services.So to avoid all these handling Work manager comes to rescue.<br />
You don’t need to write device logic to figure out what capabilities the device has and choose an appropriate API; instead, you can just hand your task off to <strong><span style="color: #008000;">WorkManager</span></strong> and let it choose the best option.</p>
<h3></h3>
<h4><strong><span style="color: #000080;">How WorkManager works</span></strong></h4>
<p>WorkManager chooses the appropriate way to run your task based on such factors as the device API level and the app state. If WorkManager executes one of your tasks while the app is running, WorkManager can run your task in a new thread in your app&#8217;s process. If your app is not running, WorkManager chooses an appropriate way to schedule a background task depending on the device API level and included dependencies, WorkManager might use <a href="https://developer.android.com/reference/android/app/job/JobScheduler.html">JobScheduler</a>, <a href="https://github.com/firebase/firebase-jobdispatcher-android#user-content-firebase-jobdispatcher-">Firebase JobDispatcher</a>, or <a href="https://developer.android.com/reference/android/app/AlarmManager.html">AlarmManager</a>.</p>
<ol>
<li>For devices whose API>;=23 it will use <strong><span style="color: #008000;">JobScheduler</span></strong> as the best option to schedule the task.</li>
<li>For devices whose API>;=14 and in which google play services installed, it will use <strong><span style="color: #008000;">FirebaseJobDispatcher</span></strong>.</li>
<li>For devices whose API<;14 it will use <strong><span style="color: #008000;">AlarmManager</span></strong> or <strong><span style="color: #008000;">BroadcastReceivers</span></strong>.</li>
</ol>
<h4><span style="color: #000080;"><strong>FEATURES OF WORKMANAGER</strong></span></h4>
<ul>
<li><span style="color: #0000ff;"><strong style="font-style: inherit;">Guaranteed, constraint-aware execution : </strong></span>Let’s say If I wanna upload a photo. I only wanna do it when the device has the network, that’s the constraint.</li>
<li><span style="color: #0000ff;"><strong style="font-style: inherit;">Respectful of system background restrictions : </strong></span>Let’s say If your app in a doze mode it won’t wake up your phone just to do those work.</li>
<li><span style="color: #0000ff;"><strong style="font-style: inherit;">Backwork compatible with or without Google play services :</strong></span> It uses internally <strong><span style="color: #008000;">AlarmManager</span></strong> and <strong><span style="color: #008000;">BroadcatsReceiver</span></strong> for device which don’t have google play services installed.</li>
<li><strong style="font-style: inherit;"><span style="color: #0000ff;">Queryable </span>: </strong>If you have a queue of work, you can actually check what’s the state. Is it running right now, has it succeeds or fails.</li>
<li><strong style="font-style: inherit;"><span style="color: #0000ff;">Chainable </span>: </strong>It is also chainable like you have work A depending on work B and C which in turn out a dependent on work D.</li>
<li><strong style="font-style: inherit;"><span style="color: #0000ff;">Opportunistic </span>: </strong>This means WorkManager tried to execute the work in your process as soon as the constraint match- without actually needing <span style="color: #0000ff;"><strong style="font-style: inherit;">JobScheduler</strong></span>.</li>
</ul>
<h4><span style="color: #000080;">WORKMANAGER CORE CLASSES</span></h4>
<p>There are few WorkManager classes you need to know about.</p>
<ul>
<li><strong style="font-style: inherit;"><span style="color: #0000ff;">Worker</span> :</strong> specifies what task you need to perform. The WorkManager APIs include an abstract <strong><span style="color: #008000;"><a style="color: #008000;" href="https://developer.android.com/reference/androidx/work/Worker.html">Worker</a></span></strong> You extend this class and perform the work here.</li>
<li><strong><span style="color: #0000ff;">WorkRequest</span> : </strong>represents an individual task. A <strong><span style="color: #008000;"><a style="color: #008000;" href="https://developer.android.com/reference/androidx/work/WorkRequest.html">WorkRequest</a></span></strong> object specifies which Worker class should perform the task. However, you can also add details to the WorkRequest object, specifying things like the circumstances under which the task should run. Every WorkRequest has an autogenerated <strong><span style="color: #008000;">unique ID</span></strong>; you can use the ID to do things like cancel a queued task or get the task&#8217;s state. WorkRequest is an abstract class; in your code, you&#8217;ll be using one of the direct subclasses, <strong><span style="color: #008000;"><a style="color: #008000;" href="https://developer.android.com/reference/androidx/work/OneTimeWorkRequest">OneTimeWorkRequest</a></span></strong> or <strong><a href="https://developer.android.com/reference/androidx/work/PeriodicWorkRequest"><span style="color: #008000;">PeriodicWorkRequest</span></a>.</strong></li>
</ul>
<p><span style="color: #000080;"><strong> Types of WorkRequest</strong></span></p>
<p><strong style="font-style: inherit;"><span style="color: #0000ff;"> OneTimeWorkRequest</span> : </strong>For task that you need to run only once.</p>
<p><strong style="font-style: inherit;"><span style="color: #0000ff;"> PeriodicWorkRequest</span> : </strong>For task that you need to perform repeatedly.</p>
<ul>
<li><span style="color: #0000ff;"><strong>WorkManager :</strong></span> enqueues and manages the work requests. You pass your WorkRequest object to <strong><span style="color: #008000;"><a style="color: #008000;" href="https://developer.android.com/reference/androidx/work/WorkManager.html">WorkManager</a></span></strong> to enqueue the task.</li>
</ul>
<h4><strong> </strong><span style="color: #000080;"><strong>How to use WorkManager</strong></span></h4>
<p>So, enough of this theory let’s see how we can integrate <span style="color: #008000;"><strong style="font-style: inherit;">WorkManager</strong></span> in Android app.</p>
<p>First, open your app level <strong><span style="color: #008000;">build. gradle</span></strong> file and add a dependency.</p>
<p><span style="color: #000080;"><strong>Add dependency</strong></span><strong> </strong></p>
<pre><code>dependencies {
implementation "android.arch.work:work-runtime:1.0.0-alpha02" }</code></pre>
<h5><span style="color: #000080;"><strong>Extend the worker class</strong></span></h5>
<p>Now the setup part is done. Let’s see how we can make a simple <strong><span style="color: #008000;">Worker</span>.</strong> <strong> </strong></p>
<!-- WP QUADS Content Ad Plugin v. 2.0.98.1 -->
<div class="quads-location quads-ad2" id="quads-ad2" style="float:none;margin:0px;">

</div>

<pre><code>Class UploadImageWorker: Worker() {

override fun doWork(): WorkerResult {

// <strong><span style="color: #008000;">Upload image to FirebaseStorage</span></strong>
uploadImage()

// <strong><span style="color: #008000;">Indicate success or failure with your return value:</span></strong>
return WorkerResult.SUCCESS

<span style="color: #008000;"><strong>// (Returning RETRY tells WorkManager to try this task again
// FAILURE says not to try again.)</strong></span>

}

}</code></pre>
<p>The <strong><span style="color: #008000;">doWork</span> </strong>method actually runs on a background thread. WorkManager automatically runs this function on a background thread you don’t need to do run. You see <strong><span style="color: #008000;">doWork</span> </strong>method have return type <strong><span style="color: #008000;">WorkerResult</span>. </strong>So, we need to return <span style="color: #008000;"><strong>Success</strong></span> if everything goes well and <strong><span style="color: #008000;">Failure</span> </strong>if any error occurred.</p>
<h5><strong><span style="color: #000080;">Create a WorkRequest</span></strong></h5>
<p>Now let’s see how we can call this <strong><span style="color: #000080;">UploadImageWorker</span></strong> class by creating request.</p>
<pre><code>val uploadImageRequest = OneTimeWorkRequest.Builder(UploadImageWorker::class.java)
 .build()
val workManager = WorkManager.getInstance()
workManager.enqueue(uploadImageRequest)</code></pre>
<h5><span style="color: #000080;"><strong>Adding Contraints</strong></span></h5>
<ul>
<li><strong><span style="color: #008000;">Constraints</span></strong> specifies restrictions on when the task should run (for example, &#8220;only when connected to the network&#8221;). You create the Constraints object with <strong><span style="color: #008000;">Constraints.Builder</span></strong>, and pass the Constraints to the <strong><span style="color: #008000;">WorkRequest.Builder</span></strong> before creating the <strong><span style="color: #008000;">WorkRequest</span></strong>.</li>
<li>Soon after this request enqueued it will start uploading images. Now, what if you lose connectivity in the middle of this or even before this what if you do not have connectivity. You actually wanna constraints in this case.</li>
<li>The following shows how to add constraints in <span style="color: #008000;"><strong>WorkRequest</strong></span>.</li>
</ul>
<pre><code>val constraints = Constraints.Builder()
 .setRequiredNetworkType(NetworkType.CONNECTED)
 .build()


val uploadImageRequest = OneTimeWorkRequest.Builder(UploadImageWorker::class.java)
 .setConstraints(constraints)
 .build()
val workManager = WorkManager.getInstance()
workManager.enqueue(uploadImageRequest)</code></pre>
<h5><span style="color: #000080;"><strong>Observing Work</strong></span></h5>
<p>Now let’s say I want to observe the request. I wanna show a progress bar while this work is executing and I wanna hide the spinner when it’s done.</p>
<p>The following shows how to observe a <strong><span style="color: #008000;">WorkRequest</span>.</strong></p>
<pre><code>workManager.getStatusById(uploadImageRequest.id).observe(this, Observer {
 if(it!=null &;&; it.state.isFinished)
 {
 progressBar.setVisbility(GONE)
 }
});</code></pre>
<p><span style="color: #0000ff;"><strong>it</strong> <strong>:</strong></span> refers to <strong><span style="color: #008000;">WorkStatus</span></strong> contains information about a particular task.</p>
<p>The <strong><span style="color: #008000;">WorkManager</span></strong> provides a <strong><span style="color: #008000;">LiveData</span></strong> for each WorkRequest .The <span style="color: #008000;"><strong>LiveData</strong></span> holds a <strong><span style="color: #008000;">WorkStatus</span></strong> object; by observing that <strong><span style="color: #008000;">LiveData</span></strong>, you can determine the current status of the task, and get any returned values after the task finishes.</p>
<h5><span style="color: #000080;">Canceling a Task</span></h5>
<p>You can cancel a task after you enqueue it. To cancel the task, you need its work ID, which you can get from the <strong><span style="color: #008000;">WorkRequest</span></strong> object. For example, the following code cancels the <strong><span style="color: #008000;">uploadImageRequest</span></strong> :</p>
<pre><code>val workManager = WorkManager.getInstance()
workManager.cancelWorkById(uploadImageRequest.id)</code></pre>
<p><strong><span style="color: #0000ff;">Note</span></strong>:-We can also set tag in work request using <strong><span style="color: #008000;">addTag</span></strong>() method and can use this tag for query work status or cancelling the task instead of using <strong><span style="color: #008000;">workId</span></strong>.We can also set multiple tags on single request.</p>
<h5><span style="color: #000080;"><strong>Running Multiple Request</strong></span></h5>
<p>Now let’s say I want to upload multiple images in parallel. The following shows how to execute requests in parallel.</p>
<pre><code>val uploadImageRequest1 = OneTimeWorkRequest.Builder(UploadImageWorker::class.java)
 .build()

val uploadImageRequest2 = OneTimeWorkRequest.Builder(UploadImageWorker::class.java)
 .build()

val uploadImageRequest3 = OneTimeWorkRequest.Builder(UploadImageWorker::class.java)
 .build()

val workManager = WorkManager.getInstance()
workManager.enqueue(uploadImageRequest1,uploadImageRequest2,uploadImageRequest3)</code></pre>
<p>These all work requests will be executed in parallel and everytime the order may differ.</p>
<h5><span style="color: #000080;">Recurring tasks</span></h5>
<p>You might have a task that you need to perform repeatedly. For example, before uploading the list of images to firebase storage you want to check whether the list of images is in the compressed form or not by calling <strong><span style="color: #008000;">compressCheckRequest</span></strong> every one hour.</p>
<p>To create a recurring task, use the <span style="color: #008000;"><strong><a style="color: #008000;" href="https://developer.android.com/reference/androidx/work/PeriodicWorkRequest.Builder.html">PeriodicWorkRequest.Builder</a></strong></span> class to create a <strong><span style="color: #008000;"><a style="color: #008000;" href="https://developer.android.com/reference/androidx/work/PeriodicWorkRequest.html">PeriodicWorkRequest</a></span></strong> object, then enqueue the <strong><span style="color: #008000;">PeriodicWorkRequest</span></strong> the same way you would a <strong><span style="color: #008000;">OneTimeWorkRequest</span></strong> object.</p>
<pre><code>val compressCheckRequest = PeriodicWorkRequest.Builder(CompressCheckWorker::class.java, 1,
 TimeUnit.HOURS)
 .build()

val workManager = WorkManager.getInstance()
workManager.enqueue(compressCheckRequest)</code></pre>
<h5><span style="color: #000080;">Chained tasks</span></h5>
<p>Your app might need to run several tasks in a particular order. <strong><span style="color: #008000;">WorkManager</span></strong> allows you to create and enqueue a work sequence that specifies multiple tasks, and what order they should run in.</p>
<p>For example,here I will first compress the list of images then upload it in firebase storage and then I will save the imageUrl in firebase database .The tasks must be run in the same order .</p>
<pre><code>class CompressImageWorker : Worker() {
 override fun doWork(): WorkerResult {
 <strong><span style="color: #008000;">//compress image
 //compressImage()</span></strong>
 return WorkerResult.SUCCESS;
 }
}

class UploadImageWorker : Worker() {
 override fun doWork(): Worker.WorkerResult {
 <strong><span style="color: #008000;">//upload image to firebase storage
 //uploadImage()</span></strong>
 return WorkerResult.SUCCESS
 }
}

class SaveImageWorker : Worker() {
 override fun doWork(): WorkerResult {
 <strong><span style="color: #008000;">//save image to firebase database
 //saveImage()</span></strong>
 return WorkerResult.SUCCESS
 }
}

val compressImageRequest = OneTimeWorkRequest.Builder(CompressImageWorker::class.java)
 .setConstraints(constraints)
 .build()

val uploadImageRequest = OneTimeWorkRequest.Builder(UploadImageWorker::class.java)
 .setConstraints(constraints)
 .build()
val saveImageRequest = OneTimeWorkRequest.Builder(SaveImageWorker::class.java)
 .setConstraints(constraints)
 .build()

val workManager = WorkManager.getInstance()

workManager.beginWith(compressImageRequest).then(uploadImageRequest).then(saveImageRequest).enqueue()</code></pre>
<p>I hope that this post helps you in understanding the basics of WorkManager.Thank You for being Here.

