How to Read Your Schedule From Work
WorkManager is a useful and important component of Android Jetpack. It allows the app to practice things in the background even when the app is exited or the device is restarted.
WorkManager also has many advantages over its predecessors. For example, it'due south battery conscious, allows you to determine the conditions for your chore to run such every bit having a Wi-Fi connectedness, flexible retrying, and integration with Coroutines and RxJava.
In this tutorial, you lot'll build WorkManagerApp. The app downloads an epitome from a URL and saves the image to the device in the groundwork. During the process, you'll acquire about:
- WorkManager basics
- Creating different workers and querying work progress
- WorkManager initialization types
- Testing your workers
Getting Started
Download the materials using the Download Materials push at the top or bottom of this tutorial. Open Android Studio 4.1.two or afterward and import the starter projection.
Build and run the project. You'll run across the following screen:
Looking Into WorkManager
WorkManager is a Jetpack Library that allows you to run deferrable jobs.
To sympathize how WorkManager operates under the hood, you lot demand to know how it interacts with the Android operating system regarding:
- Persisting requests
- Running your requests
Persisting Requests
Once you enqueue your work asking, WorkManager stores it in the database, which acts as a Single Source of Truth.
Later this, WorkManager sends the work asking to JobScheduler for API 23 and in a higher place. For API below 23, WorkManager performs a further cheque. If the device has Play Services installed, WorkManager sends the piece of work request to GCM Network Manager. If it'south not installed, WorkManager uses Alarm Director to run the piece of work.
WorkManager does all this for you. :] Next, you lot'll wait at how WorkManager actually runs your work request.
Running Your Asking
JobScheduler, GCM Network Manager and Warning Managing director are enlightened of your work. They'll get-go your application if need exist, given that the device meets all the constraints. In turn, they'll request WorkManager to run your work.
There'south as well GreedyScheduler, which runs within the app process. Hence, it doesn't start your app if it's in the background. GreedyScheduler isn't affected by the OS.
Now that you lot understand how WorkManager operates, information technology's time to define your first WorkRequest.
Defining Your Work
You define your work by extending from Worker
and overriding doWork
. doWork
is an asynchronous method that executes in the background.
WorkManager has back up for long-running tasks. It keeps the process in these tasks live when the work is running. Instead of a normal Worker
, you'll utilise a ListenableWorker
if y'all're in Coffee or a CoroutineWorker
if you're using Kotlin Coroutines.
First, navigate to ImageDownloadWorker.kt inside the workers package. You'll run into a class similar the one beneath:
course ImageDownloadWorker( private val context: Context, private val workerParameters: WorkerParameters ) : CoroutineWorker(context, workerParameters) { override suspend fun doWork(): Result { TODO("Not even so implemented") } }
The code to a higher place does the following:
- The
ImageDownloadWorker
course extendsCoroutineWorker
. -
ImageDownloadWorker
requires instances ofContext
andWorkerParameters
as parameters in the constructor. You pass them toCoroutineWorker
, too. - It overrides
doWork()
, asuspend
method. It can do long-running tasks off the main thread.
doWork()
is pretty bare. You lot'll add the code to do work in this method shortly.
Navigate to ImageUtils.kt and add the post-obit extension role:
fun Context.getUriFromUrl(): Uri? { // 1 val imageUrl = URL( "https://images.pexels.com/photos/169573/pexels-photo-169573.jpeg" + "?auto=shrink&cs=tinysrgb&dpr=2&h=650&w=940" ) // 2 val bitmap = imageUrl.toBitmap() // 3 var savedUri: Uri? = null bitmap?.apply { savedUri = saveToInternalStorage(this@getUriFromUrl) } render savedUri }
Here'south a breakdown of what the code to a higher place does:
-
imageUrl
converts a link to a qualified URL. - Side by side, you lot convert
imageUrl
to a bitmap usingtoBitmap()
. - Concluding, yous save the paradigm bitmap to internal storage. Moreover, you get the URI of the path to the prototype'due south storage location.
Caput to ImageDownloadWorker.kt. Supplant TODO("Not even so implemented") with the following code:
// 1 filibuster(10000) // 2 val savedUri = context.getUriFromUrl() // 3 return Consequence.success(workDataOf("IMAGE_URI" to savedUri.toString()))
Here'south a code breakdown:
- The image downloads quickly. To simulate a near existent-earth situation, you add a delay of 10,000 milliseconds so the work tin can take fourth dimension.
- You get the URI from the extension function you added in the previous footstep.
- Final, one time you take the URI, you return a successful response to notify that your work has finished without failure.
workDataOf()
converts a list of pairs to aData
object. AData
object is a fix of central/value pairs used as inputs/outputs forListenableWorker
'due south.IMAGE_URI
is a key for identifying the consequence. You're going to employ it to get the value from this worker.
Now, you might run into some warnings due to missing imports. At the top of the file, add:
import androidx.work.workDataOf import com.raywenderlich.android.workmanager.utils.getUriFromUrl import kotlinx.coroutines.delay
Y'all have defined your work. Next, y'all'll create a WorkRequest
to run the piece of work.
Creating Your WorkRequest
For your scheduled work to run, the WorkManager service has to schedule it. A WorkRequest
contains information of how and when your work will run.
You tin schedule your work to run either periodically or once.
For running work periodically, you'll use a PeriodicWorkRequestBuilder
. For quondam work, you'll use OneTimeWorkRequestBuilder
.
Creating a 1-Time WorkRequest
To create a 1-time request, you'll begin by adding WorkManager initialization. Navigate to HomeActivity.kt. Add this at the height class definition:
private val workManager past lazy { WorkManager.getInstance(applicationContext) }
Here, you create an instance of WorkManager as a top-course variable. Members of HomeActivity
can utilize this WorkManager case. Exist sure to add the WorkManager import when prompted to practise so.
Second, add together the following method below onCreate
:
private fun createOneTimeWorkRequest() { // i val imageWorker = OneTimeWorkRequestBuilder<ImageDownloadWorker>() .setConstraints(constraints) .addTag("imageWork") .build() // ii workManager.enqueueUniqueWork( "oneTimeImageDownload", ExistingWorkPolicy.KEEP, imageWorker ) }
In the code in a higher place, you:
- Create your
WorkRequest
. Yous besides set up constraints to the piece of work. Additionally, you add a tag to make your work unique. You lot tin can utilise this tag to cancel the work and observe its progress, too. - Finally, yous submit your work to WorkManager past calling
enqueueUniqueWork
.
You lot might see some warnings due to missing imports. At the height of the file, add:
import androidx.work.ExistingWorkPolicy import androidx.piece of work.OneTimeWorkRequestBuilder import com.raywenderlich.android.workmanager.workers.ImageDownloadWorker
Still, yous'll come across the constraints
is nonetheless highlighted in cherry-red. To resolve this, add the following lawmaking below your WorkManager initialization at the top of the class:
private val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresStorageNotLow(true) .setRequiresBatteryNotLow(true) .build()
The post-obit constraints are ready for work to run. The device must have:
- An active network connectedness
- Enough storage
- Plenty battery
Inside onCreate
, add the following code below requestStoragePermissions()
:
activityHomeBinding.btnImageDownload.setOnClickListener { showLottieAnimation() activityHomeBinding.downloadLayout.visibility = View.GONE createOneTimeWorkRequest() }
In the code above, you call createOneTimeWorkRequest()
when you tap Kickoff Image DOWNLOAD. Yous're likewise showing the animation and hiding the layout every bit you wait for your work to complete.
Build and run the app. The UI remains the same.
Tap Start IMAGE DOWNLOAD. Notice that the animation doesn't terminate. Don't worry, you'll fix this behavior in the adjacent steps.
Observing Piece of work Progress
With WorkManager, you can observe the progress of your work when the app is in the foreground.
To observe your work's progress, add the following method below createOneTimeWorkRequest()
:
private fun observeWork(id: UUID) { // i workManager.getWorkInfoByIdLiveData(id) .notice(this, { info -> // two if (info != null && info.country.isFinished) { hideLottieAnimation() activityHomeBinding.downloadLayout.visibility = View.VISIBLE // iii val uriResult = info.outputData.getString("IMAGE_URI") if (uriResult != null) { showDownloadedImage(uriResult.toUri()) } } }) }
The code in a higher place:
- Gets the piece of work information using the work ID and returns it as observable
LiveData
. - Adds a null check for the work information and the work completion.
- Gets the data from your piece of work and displays the paradigm. It uses the
IMAGE_URI
key from the worker to get the specific value. Without this key, information technology tin can't become the data from your work.
Add together a telephone call to observeWork()
at the bottom of createOneTimeWorkRequest()
:
observeWork(imageWorker.id)
You pass the work ID to observeWork()
. You utilize this ID to detect information about this particular work.
Build and run the app.
Tap START Epitome DOWNLOAD to start the download. Once the download completes, yous'll come across the following screen:
At times, you'll need to create work that runs periodically, rather than once. In the adjacent section, y'all'll create such periodic work requests.
Creating a Periodic WorkRequest
Occasionally, your work needs to run several times, such every bit daily backups of a messaging app. In such cases, you use a PeriodicWorkRequest
to create your WorkRequest
.
Add the following code below onCreate
:
private fun createPeriodicWorkRequest() { // 1 val imageWorker = PeriodicWorkRequestBuilder<ImageDownloadWorker>( 15, TimeUnit.MINUTES) .setConstraints(constraints) .addTag("imageWork") .build() // 2 workManager.enqueueUniquePeriodicWork( "periodicImageDownload", ExistingPeriodicWorkPolicy.Proceed, imageWorker ) observeWork(imageWorker.id) }
In the code to a higher place, y'all:
- Apply
PeriodicWorkRequestBuilder
to define your piece of work. Detect that it takes time as a parameter. A brake requires the interval between successive executions of your work to exist at least 15 minutes. - Submit the work to WorkManager past calling
enqueueUniquePeriodicWork
. Y'all need to laissez passer theuniqueWorkName
,existingPeriodicWorkPolicy
and theimageWorker
itself.
Within onCreate
, supplant createOneTimeWorkRequest()
with createPeriodicWorkRequest()
. The code should at present be equally follows:
activityHomeBinding.btnImageDownload.setOnClickListener { showLottieAnimation() activityHomeBinding.downloadLayout.visibility = View.GONE createPeriodicWorkRequest() }
Build and run the app. Tap Start Epitome DOWNLOAD to start the download. You lot'll notice that the animation doesn't disappear. This is because periodic work never ends and merely has CANCELLED
state. After each run, the work volition be re-run regardless of the previous state.
Creating a Delayed WorkRequest
A delayed WorkRequest
is a Old WorkRequest whose execution is delayed past a given duration.
First, add the following code below onCreate
:
private fun createDelayedWorkRequest() { val imageWorker = OneTimeWorkRequestBuilder<ImageDownloadWorker>() .setConstraints(constraints) .setInitialDelay(30, TimeUnit.SECONDS) .addTag("imageWork") .build() workManager.enqueueUniqueWork( "delayedImageDownload", ExistingWorkPolicy.KEEP, imageWorker ) observeWork(imageWorker.id) }
Notice the improver of setInitialDelay(thirty, TimeUnit.SECONDS)
, which takes the amount of time you want to delay your work.
Inside onCreate
, replace createPeriodicWorkRequest()
with createDelayedWorkRequest()
. Your final result will exist:
activityHomeBinding.btnImageDownload.setOnClickListener { showLottieAnimation() activityHomeBinding.downloadLayout.visibility = View.GONE createDelayedWorkRequest() }
Build and run the app. Tap START Prototype DOWNLOAD to commencement the download, which delays for thirty seconds. Later on this filibuster is consummate, your piece of work begins to run. When information technology finishes, you'll see the post-obit screen:
Yous've seen how to create your work and define and run your WorkRequest
. It's time for you lot to acquire how to query work information.
Querying Piece of work Data
WorkManager allows y'all to write circuitous queries. You use the unique work name, tag and state, using WorkQuery
objects.
To query information nigh the work you've run, add together the following code below observeWork()
:
private fun queryWorkInfo() { // ane val workQuery = WorkQuery.Builder .fromTags(listOf("imageWork")) .addStates(listOf(WorkInfo.State.SUCCEEDED)) .addUniqueWorkNames( listOf("oneTimeImageDownload", "delayedImageDownload", "periodicImageDownload") ) .build() // ii workManager.getWorkInfosLiveData(workQuery).observe(this) { workInfos-> activityHomeBinding.tvWorkInfo.visibility = View.VISIBLE activityHomeBinding.tvWorkInfo.text = resources.getQuantityString(R.plurals.text_work_desc, workInfos.size, workInfos.size) } }
Here's what the code higher up does:
- This is a
WorkQuery
builder, and you're setting the tag, country and unique names for the works you want to get their information. - You call
getWorkInfosLiveData()
and passworkQuery
. This method returns observable data.
To wire everything up, add the following lawmaking inside onCreate
:
activityHomeBinding.btnQueryWork.setOnClickListener { queryWorkInfo() }
In the code above, you set a click listener to the QUERY WORK INFO button, which calls queryWorkInfo()
.
Build and run the app. Tap START Prototype DOWNLOAD and wait for the download to complete.
Tap QUERY WORK INFO:
The WorkQuery
returns the completed piece of work and the event is shown on the screen.
In the next section, you'll learn how to initialize WorkManager in different means.
WorkManager Initialization Types
WorkManager has ii types of initialization:
- Automatic Initialization: WorkManager initializes automatically with default configuration and no customizations. The initialization happens in your awarding
onCreate
. It can add together an extra overhead when WorkManager isn't in apply. - On-Demand Initialization: This lets you lot define WorkManager when y'all need it. It removes the overhead from app startup and in plough improves your app performance. This initialization is extremely helpful when you need more informative WorkManager logs.
Using On-Demand Initialization
To utilise On-Demand Initialization, y'all get-go need to disable automatic initialization. To achieve this, caput over to AndroidManifest.xml. Supersede TODO Add together PROVIDER
with:
<provider android:name="androidx.work.impl.WorkManagerInitializer" android:regime="${applicationId}.workmanager-init" tools:node="remove" />
Exist sure to add together the tools
import when prompted to do so. This removes the default WorkManager initializer.
2d, you'll need to change your application class to add together a new configuration provider. Head to WorkManagerApp.kt and replace the grade with the following code:
// ane class WorkManagerApp : Application(), Configuration.Provider { // 2 override fun getWorkManagerConfiguration(): Configuration { render Configuration.Builder() .setMinimumLoggingLevel(android.util.Log.DEBUG) .build() } override fun onCreate() { super.onCreate() // iii WorkManager.initialize(this, workManagerConfiguration) } }
In the code higher up:
- The awarding class extends
Configuration.Provider
. This allows y'all to provide your own custom WorkManager configuration. - You provide your own implementation of
getWorkManagerConfiguration()
, in which you provide your custom WorkManager initialization. You besides specify the minimum logging level. - Last, you initialize WorkManager with a custom configuration you lot've created.
You might see some warnings due to missing imports. At the top of the file, add:
import androidx.work.Configuration import androidx.work.WorkManager
Build and run the app. The functionality does not change. Now, you're using on-demand initialization for your WorkManager.
Testing Your Workers
Testing is 1 of the most important aspects of software development. WorkManager provides comprehensive APIs to enable you to write tests. This is very important because you lot can test your workers and confirm that everything runs as expected.
Inside the androidTest directory, create a new file named ImageDownloadWorkerTest.kt and add the following code:
course ImageDownloadWorkerTest { // ane @get:Rule var instantTaskExecutorRule = InstantTaskExecutorRule() @go:Dominion var workerManagerTestRule = WorkManagerTestRule() // ii @Examination fun testDownloadWork() { // Create Work Request val work = TestListenableWorkerBuilder<ImageDownloadWorker>(workerManagerTestRule.targetContext).build() runBlocking { val result = work.doWork() // Assert assertNotNull(outcome) } } }
To sum upwards what the above code does:
- You go
InstantTaskExecutorRule
, which swaps the background executor used by the Architecture Components with a unlike ane that executes each task synchronously. You also goWorkManagerTestRule
, which initializes WorkManager and likewise provides a context. - This is the actual test, which is to test your
ImageDownloadWorker
. You're usingTestListenableWorkerBuilder
, which runs yourWorker
. In this case, yourWorker
is aCoroutineWorker
.
Add the following imports to resolve all errors:
import androidx.curvation.core.executor.testing.InstantTaskExecutorRule import androidx.piece of work.testing.TestListenableWorkerBuilder import com.raywenderlich.android.workmanager.workers.ImageDownloadWorker import kotlinx.coroutines.runBlocking import org.junit.Assert.assertNotNull import org.junit.Dominion import org.junit.Test
Click the Run icon to the left of testDownloadWork()
. You'll see the following:
Congratulations! :] You wrote your first Worker
exam. Side by side, you'll be writing tests for your WorkRequest
.
Note: WorkManager tests need the Android platform to run. This is the reason your tests are in the androidTest directory.
Testing Delayed Piece of work
Open SampleWorker.kt inside workers and add the following code:
import android.content.Context import androidx.work.Worker import androidx.piece of work.WorkerParameters class SampleWorker ( individual val context: Context, private val workerParameters: WorkerParameters ) : Worker(context, workerParameters) { override fun doWork(): Result { return when (inputData.getString("Worker")) { "sampleWorker" -> Consequence.success() else -> Effect.retry() } } }
The class above extends from Worker
and overrides doWork()
. It checks the input information and returns success when it finds the sampleWorker
input. This SampleWorker
is for testing purposes. Information technology shows y'all how to exam normal Workers.
Head to SampleWorkerTest.kt, which is under the androidTest directory. This class is blank and has merely the rules at the top. You'll be calculation tests in this class.
Beneath workerManagerTestRule
, add the post-obit lawmaking:
@Test fun testWorkerInitialDelay() { val inputData = workDataOf("Worker" to "sampleWorker") // 1 val request = OneTimeWorkRequestBuilder<SampleWorker>() .setInitialDelay(10, TimeUnit.SECONDS) .setInputData(inputData) .build() // 2 val testDriver = WorkManagerTestInitHelper .getTestDriver(workerManagerTestRule.targetContext) val workManager = workerManagerTestRule.workManager // iii workManager.enqueue(request).result.become() // four testDriver?.setInitialDelayMet(request.id) // v val workInfo = workManager.getWorkInfoById(request.id).get() // 6 assertThat(workInfo.state, `is`(WorkInfo.State.SUCCEEDED)) }
With the code to a higher place, you:
- Create your
WorkRequest
usingOneTimeWorkRequestBuilder
. You set an initial delay of 10 seconds. Yous're also setting input data to your request. - Create a
TestDriver
, which will help in simulating the delay. You're creating an instance ofWorkManager
, too. - Enqueue your request.
- Simulate the actual delay for your work.
- Get piece of work info and output information.
- Do an exclamation to check the succeeded state in your piece of work.
To resolve import errors, add the post-obit imports at the top of the file:
import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkInfo import androidx.piece of work.testing.WorkManagerTestInitHelper import androidx.work.workDataOf import com.raywenderlich.android.workmanager.workers.SampleWorker import org.hamcrest.CoreMatchers.`is` import org.junit.Affirm.assertThat import coffee.util.concurrent.TimeUnit import org.junit.Test
Click the Run icon to the left of testWorkerInitialDelay()
. You'll see the following:
You lot've learned how to test delayed workers. Side by side, you'll examination periodic work requests.
Testing Periodic Work
Still on the SampleWorkerTest.kt, below testWorkerInitialDelay
, add together:
@Test fun testPeriodicSampleWorker() { val inputData = workDataOf("Worker" to "sampleWorker") // i val request = PeriodicWorkRequestBuilder<SampleWorker>(xv, TimeUnit.MINUTES) .setInputData(inputData) .build() // 2 val testDriver = WorkManagerTestInitHelper .getTestDriver(workerManagerTestRule.targetContext) val workManager = workerManagerTestRule.workManager // 3 workManager.enqueue(request).result.go() // 4 testDriver?.setPeriodDelayMet(request.id) // v val workInfo = workManager.getWorkInfoById(request.id).get() // 6 assertThat(workInfo.state, `is`(WorkInfo.State.ENQUEUED)) }
In this code, you:
- Create your
WorkRequest
usingPeriodicWorkRequestBuilder
, with a time interval of 10 minutes. Yous're also setting input data to your request. - Make a
testDriver
, which will aid in simulating the time interval betwixt each work. You're creating an case ofworkManager
, as well. - Enqueue your request.
- Notify the WorkManager testing framework that the interval'south duration is complete.
- Go piece of work info and output data.
- Practice an assertion to check for the enqueued state for your piece of work.
Click the Run icon to the left of testPeriodicSampleWorker()
. You'll see the following:
Y'all've now learned how to test periodic piece of work requests. Next, you'll exam constraints.
Testing Constraints
SampleWorker
needs simply two constraints: active network connection and enough bombardment. TestDriver
has setAllConstraintsMet
for simulating constraints.
In your SampleWorkerTest, below testPeriodicSampleWorker
, add:
@Test fun testAllConstraintsAreMet() { val inputData = workDataOf("Worker" to "sampleWorker") // 1 val constraints = Constraints.Architect() .setRequiredNetworkType(NetworkType.Connected) .setRequiresBatteryNotLow(true) .build() // 2 val asking = OneTimeWorkRequestBuilder<SampleWorker>() .setConstraints(constraints) .setInputData(inputData) .build() val workManager = WorkManager .getInstance(workerManagerTestRule.targetContext) // three workManager.enqueue(request).issue.get() // 4 WorkManagerTestInitHelper.getTestDriver(workerManagerTestRule.targetContext) ?.setAllConstraintsMet(asking.id) // v val workInfo = workManager.getWorkInfoById(asking.id).get() // six assertThat(workInfo.state, `is`(WorkInfo.Country.SUCCEEDED)) }
Here's a breakdown of the code higher up. Information technology:
- Creates your network and battery constraints.
- Makes your
WorkRequest
, usingOneTimeWorkRequestBuilder
. It sets your constraints to the request. It besides sets input data to your request. - Enqueues your request
- Simulates the network and battery constraints, using
WorkManagerTestInitHelper
- Gets work info and output data
- Does an assertion to check for the succeeded land for your piece of work
Click the Run icon to the left of testAllConstraintsAreMet()
. You'll see the following:
All tests have passed! :] That is truly a reason to be proud of yourself! In the next section, you're going to wait at how to create works that run in the foreground.
Creating Foreground Piece of work
For long-running tasks, you need to bear witness a persistent notification. This prevents the Android system from killing your process when your app is no longer running.
For such cases, WorkManager uses a foreground service to show a persistent notification to the user. With CoroutineWorker
, yous'll apply setForeground()
to specify that your WorkRequest
is important or long-running.
Navigate to ImageDownloadWorker.kt and add this below doWork()
:
individual fun createForegroundInfo(): ForegroundInfo { // ane val intent = WorkManager.getInstance(applicationContext) .createCancelPendingIntent(id) // ii val notification = NotificationCompat.Architect( applicationContext, "workDownload") .setContentTitle("Downloading Your Image") .setTicker("Downloading Your Image") .setSmallIcon(R.drawable.notification_action_background) .setOngoing(truthful) .addAction(android.R.drawable.ic_delete, "Cancel Download", intent) // 3 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { createChannel(notification, "workDownload") } return ForegroundInfo(ane, notification.build()) }
Here is what'southward happening:
- This is a
PendingIntent
you'll use to cancel the piece of work. - This is the bodily notification with an icon, championship and cancel action. The cancel activity is necessary for canceling work.
- You're creating a notification aqueduct for Android versions above Oreo. Then, you render
ForegroundInfo
, which you lot utilise to update your ongoing notification.
Resolve all import errors when prompted. You'll notice createChannel(notification, "workDownload")
remains highlighted in blood-red. To resolve this, add together this method below createForegroundInfo()
:
@RequiresApi(Build.VERSION_CODES.O) individual fun createChannel( notificationBuilder: NotificationCompat.Architect, id: String ) { val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationBuilder.setDefaults(Notification.DEFAULT_VIBRATE) val channel = NotificationChannel( id, "WorkManagerApp", NotificationManager.IMPORTANCE_HIGH ) channel.description = "WorkManagerApp Notifications" notificationManager.createNotificationChannel(channel) }
In the code above, you create a notification channel. The channel is necessary for devices with version Oreo and above. Add all imports as prompted by the IDE.
Now, to become the notification working, add this in doWork()
above your telephone call to delay()
:
setForeground(createForegroundInfo())
Here, you lot call setForeground()
from CoroutineWorker
to mark your work as long-running or important.
Build and run the app. Then tap on Showtime Paradigm DOWNLOAD.
One time your download image task starts, you'll encounter a persistent notification. This informs the Android operating system that your task is long-running or important. The operating arrangement won't kill your chore once your app is in the background. Once WorkManager completes the task, the notification will disappear.
Requesting Diagnostic Data from WorkManager
WorkManager provides a way to become the following information:
- Requests that have been completed in the by 24 hours
- Requests that have been scheduled
- Running work requests
This information is available for debug builds. To go this information, run this command on your terminal:
adb beat out am broadcast -a "androidx.work.diagnostics.REQUEST_DIAGNOSTICS" -p "com.raywenderlich.android.workmanager"
Your logcat displays the following data:
Where to Go From Hither?
Download the final version of this project using the Download Materials button at the top or bottom of this tutorial.
Congratulations! You learned how to use WorkManager to run one-fourth dimension, delayed, periodic, and long-running or important tasks in the background. You too learned how to write tests for your workers.
To learn more well-nigh WorkManager, check out the WorkManager official documentation.
I promise y'all enjoyed the tutorial. If you have whatsoever questions or comments, delight bring together the forum give-and-take below.
Source: https://www.raywenderlich.com/20689637-scheduling-tasks-with-android-workmanager
0 Response to "How to Read Your Schedule From Work"
Post a Comment