{"id":43880,"date":"2019-04-08T11:12:29","date_gmt":"2019-04-08T18:12:29","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/xamarin\/?p=43880"},"modified":"2019-08-30T08:32:37","modified_gmt":"2019-08-30T15:32:37","slug":"getting-started-workmanager","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/xamarin\/getting-started-workmanager\/","title":{"rendered":"Getting Started With WorkManager"},"content":{"rendered":"<p>If you need to schedule a background task on Android, you&#8217;re probably familiar with all of the various ways to accomplish this such as:<\/p>\n<ul>\n<li>Google Cloud Messaging<\/li>\n<li>Firebase Cloud Messaging<\/li>\n<li>DownloadManager<\/li>\n<li>Foreground Service<\/li>\n<li>Alarm Manager<\/li>\n<li>etc<\/li>\n<\/ul>\n<h2>WorkManager<\/h2>\n<p>Give a warm welcome to WorkManager. WorkManager is a library that makes it easy to schedule deferrable, asynchronous tasks even if the app exits or the device restarts. It was designed to be backwards compatible to API 14 and does so by wrapping JobScheduler, AlarmManager, and BroadcastReceivers all in one.<\/p>\n<p>Using JobScheduler your app will be running on a device that is API 23+. Anything below, you&#8217;ll be using a combination of AlarmManager + BroadcastReceivers.<\/p>\n<h3>How is work executed?<\/h3>\n<p>Work is fed to an executor to guarantee the work is done.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-43882\" src=\"http:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/workexecution.png\" alt=\"\" width=\"757\" height=\"308\" srcset=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/workexecution.png 757w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/workexecution-300x122.png 300w\" sizes=\"(max-width: 757px) 100vw, 757px\" \/><\/p>\n<p>The executor will complete the work so long as it meets the constraints that you set up when you enqueue the work.<\/p>\n<h3>Async by Default<\/h3>\n<p>Every operation is asynchronous. Thus you won&#8217;t have to worry about threading at all. The operations are saved in a WorkManager database that is the source of truth for any enqueued, successful, or cancelled operations.<\/p>\n<h3>When does work end?<\/h3>\n<ul>\n<li>Upon the work finishing.<\/li>\n<li>In the event that the constraints are no longer met (Network could be lost, Phone is no longer plugged in, etc).<\/li>\n<li>The OS decided to kill your enqueued work.<\/li>\n<li>You cancelled your work.<\/li>\n<\/ul>\n<h3>Lifetime of work<\/h3>\n<h4>One Time Work<\/h4>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-43883\" src=\"http:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/onetimework.png\" alt=\"\" width=\"731\" height=\"299\" srcset=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/onetimework.png 731w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/onetimework-300x123.png 300w\" sizes=\"(max-width: 731px) 100vw, 731px\" \/><\/p>\n<p>This type of work&#8217;s final state is <span class=\"lang:default decode:true crayon-inline \">Succeeded<\/span>\u00a0when completed. Otherwise it will go into a <span class=\"lang:default decode:true crayon-inline\">Failed<\/span>\u00a0or <span class=\"lang:default decode:true crayon-inline\">Cancelled<\/span>\u00a0state.<\/p>\n<h4>Periodic Work<\/h4>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-43884\" src=\"http:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/periodicwork.png\" alt=\"\" width=\"545\" height=\"284\" srcset=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/periodicwork.png 545w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/periodicwork-300x156.png 300w\" sizes=\"(max-width: 545px) 100vw, 545px\" \/><\/p>\n<p>This type of work does not have a final state because it has either a finite or infinite amount of iterations. Thus it will continuously enqueue and run.<\/p>\n<h2>Getting Started<\/h2>\n<h3>Installing the NuGet<\/h3>\n<p>Using NuGet, install the <span class=\"lang:default decode:true crayon-inline \">Xamarin.Android.Arch.Work.Runtime<\/span>\u00a0\u00a0package into your Android application. <strong>Make sure your application is targeting Android Pie (API 28) or greater.<\/strong><\/p>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-43881\" src=\"http:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/nuget-1.png\" alt=\"\" width=\"1509\" height=\"730\" srcset=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/nuget-1.png 1509w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/nuget-1-300x145.png 300w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/nuget-1-768x372.png 768w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2019\/04\/nuget-1-1024x495.png 1024w\" sizes=\"(max-width: 1509px) 100vw, 1509px\" \/><\/p>\n<p><a href=\"https:\/\/www.nuget.org\/packages\/Xamarin.Android.Arch.Work.Runtime\/\">https:\/\/www.nuget.org\/packages\/Xamarin.Android.Arch.Work.Runtime\/<\/a><\/p>\n<h3>Creating a background task<\/h3>\n<p>A task is defined using the <code>Worker<\/code> class. The <code>DoWork()<\/code> method is ran on a background thread provided by WorkManager.<\/p>\n<p>To create a background task, extend the <code>Worker<\/code> class and override the <code>DoWork()<\/code> method. For example, to create a <code>Worker<\/code> that calculates two numbers, you can do the following:<\/p>\n<pre><code>public class CalculatorWorker : Worker\r\n    {\r\n        public CalculatorWorker(Context context, WorkerParameters workerParameters) : base(context, workerParameters)\r\n        {\r\n\r\n        }\r\n        public override Result DoWork()\r\n        {\r\n            var taxReturn = CalculateTaxes();\r\n            Android.Util.Log.Debug(\"CalculatorWorker\", $\"Your Tax Return is: {taxReturn}\");\r\n            return Result.InvokeSuccess();\r\n        }\r\n\r\n        public double CalculateTaxes()\r\n        {\r\n            return 2000;\r\n        }\r\n    }\r\n<\/code><\/pre>\n<p>The <code>Result<\/code> returned from the <code>DoWork()<\/code> method informs you whether the task:<\/p>\n<ul>\n<li>Finished successfully via <code>Result.Success()<\/code><\/li>\n<li>Failed gracefully via <code>Result.Failure()<\/code><\/li>\n<li>Needs another attempt via <code>Result.Retry()<\/code><\/li>\n<\/ul>\n<p><strong>Note: <\/strong>Your worker only knows about the state passed into it by <code>WorkerParameters<\/code>.<\/p>\n<h3>When and how a task should run?<\/h3>\n<p>While a <code>Worker<\/code> defines the work to be done, a <code>WorkRequest<\/code> defines when and how the work should run. These tasks may be one time or periodic. You can use <code>OneTimeWorkRequest<\/code> for one time requests, and you can use <code>PeriodicTimeWorkRequest<\/code> for period time requests.<\/p>\n<p>Here&#8217;s how you would build the <code>WorkRequest<\/code> for our <code>Worker<\/code>:<\/p>\n<pre class=\"lang:default decode:true \">PeriodicWorkRequest taxWorkRequest = PeriodicWorkRequest.Builder.From&lt;CalculatorWorker&gt;(TimeSpan.FromMinutes(20)).Build();<\/pre>\n<h3>Running the task<\/h3>\n<p>Once you&#8217;ve built the <code>Worker<\/code> and the <code>WorkRequest<\/code>, you are ready to enqueue it using <code>WorkManager<\/code> and the <code>Enqueue()<\/code> method.<\/p>\n<pre class=\"lang:default decode:true \">WorkManager.Instance.Enqueue(taxWorkRequest);<\/pre>\n<h3>Seeing the task<\/h3>\n<p>We can then use <span class=\"lang:default decode:true crayon-inline \">adb logcat<\/span>\u00a0 to view our task.<\/p>\n<pre class=\"lang:default decode:true \">2019-03-27 13:11:51.240 6364-6402\/com.companyname D\/CalculatorWorker: Your Tax Return is: 2000\r\n2019-03-27 13:11:51.242 6364-6390\/com.companyname I\/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=3735e0f9-fc12-41aa-9f51-ac856b6eac18, tags={ md5592692d8f1b606f6fbb81503ff802e0e.CalculatorWorker } ]\r\n2019-03-27 13:21:33.020 6364-6404\/com.companyname D\/CalculatorWorker: Your Tax Return is: 2000\r\n2019-03-27 13:21:33.023 6364-6390\/com.companyname I\/WM-WorkerWrapper: Worker result SUCCESS for Work [ id=54daa9ec-d81f-4de1-b138-d5ff6349b088, tags={ md5592692d8f1b606f6fbb81503ff802e0e.CalculatorWorker } ]<\/pre>\n<h2>Summary<\/h2>\n<p>Use WorkManager for your background task needs in Android. The API is straight-forward and friendly to developers. Don&#8217;t worry about managing the lifecycle of the device and let WorkManager do the work for you.<\/p>\n<p><strong>GitHub Sample:\u00a0<\/strong><a href=\"https:\/\/github.com\/JonDouglas\/WorkManagerSample\">https:\/\/github.com\/JonDouglas\/WorkManagerSample<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Give a warm welcome to WorkManager. WorkManager is a library that makes it easy to schedule deferrable, asynchronous tasks even if the app exits or the device restarts. It was designed to be backwards compatible to API 14 and does so by wrapping JobScheduler, AlarmManager, and BroadcastReceivers all in one.<\/p>\n","protected":false},"author":551,"featured_media":43883,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[313,2,387],"tags":[5],"class_list":["post-43880","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-developers","category-education","tag-android"],"acf":[],"blog_post_summary":"<p>Give a warm welcome to WorkManager. WorkManager is a library that makes it easy to schedule deferrable, asynchronous tasks even if the app exits or the device restarts. It was designed to be backwards compatible to API 14 and does so by wrapping JobScheduler, AlarmManager, and BroadcastReceivers all in one.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/43880","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/users\/551"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/comments?post=43880"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/43880\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media\/43883"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media?parent=43880"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/categories?post=43880"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/tags?post=43880"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}