rgoncalv
rgoncalv

Reputation: 6035

Android WorkManager - how to delay task?

I am building a functionality that will allow merchants to set the schedule of their business. Such functionality would automatically change the variable open to true and false accordingly to the times the merchant set in each day of the week. Therefore, there would be a total of 14 possible different times.

I am trying to build a recurrent background task that would accomplish such a thing using WorkManager, the new Android Architecture Components library.

val scheduleStartWork = PeriodicWorkRequest.Builder(ScheduleWorker::class.java, 7, TimeUnit.DAYS)
                .setInputData(Data.Builder().putBoolean("isStart", true).build())
                .setScheduleRequestedAt(diff_time, TimeUnit.MILLISECONDS)
                .addTag(weekdays[index])
                .build()

It's giving me the following APILibraryException error though:

Builder.setScheduleRequestedAt can only be called from within the same library group

My questions:

1) Is it setScheduleRequestedAt the right method to call if I want to delay the scheduling by diff_time?

2) If so, how can I solve this problem?

PS: diff_time is the difference, in milliseconds, to each of the corresponding hours of each day set by the user. Example: Monday-Friday = 08:00, Sat-Sun= 10:00.

Upvotes: 12

Views: 12866

Answers (3)

pfmaggi
pfmaggi

Reputation: 6496

UPDATE

Since WorkManager v2.1-alpha02 it is now possible add an initial delay to a PeriodicWorkRequest. Now your call became simply:

val scheduleStartWork = PeriodicWorkRequest.Builder(ScheduleWorker::class.java, 7, TimeUnit.DAYS)
                .setInputData(Data.Builder().putBoolean("isStart", true).build())
                .setInitialDelay(diff_time, TimeUnit.MILLISECONDS)
                .addTag(weekdays[index])
                .build()

Note because the setInitialDelay has been introduced in the parent class, WorkRequest, this introduced a binary change moving from v2.0 to v2.1 for the OneTimeWorkRequest#setInitialDelay() method. This means that to use the new library you need to recompile the project when upgrading from v2.0.

Follows original answer

It's not possible to delay the first run of a periodic task with WorkManager.

Your best option is to use a OneTimeWorker with the delay that you want and from there you can enqueue your periodic worker with the period you want.

There's a feature request on WorkManager's issue tracker with an explanation for this workaround that you can use as a reference.

Note: because of how the minimum interval works, you cannot build a periodic work request that is executed at a recurring time, e.g. every day at 4:00 AM. You can specify a 24 hours repeat interval, but this can get the worker executed at 4:05AM the first day, 6:00AM the second, 6:10 AM the third day and so on. If you need to execute a worker at the same time every day, your best option is to use a OneTimeWorkRequest with an initial delay:

OneTimeWorkRequest save = new OneTimeWorkRequest
            .Builder(SaveImageToFileWorker.class)
            .setConstraints(constraints)
            .setInitialDelay(24, TimeUnit.HOURS)
            .addTag(TAG_OUTPUT)
            .build();

When the worker has been completed, you can reschedule it with a Delay so that it is going to be fired at the correct time (the exact time that the worker is going to be executed depends on the constraints that you’re using when creating the work request).

Upvotes: 19

Manmohan Soni
Manmohan Soni

Reputation: 6621

You need to update the work manager library version to 2.1.0-alpha03. In the version WorkManager provides the functionality to add initial delay in task.

Then you need to use the method setInitialDelay(). Following is the implementation to use the same in a way to achieve specific time trigger work:

long initialDelayInSeconds = (futureSpecificTime - System.currentTimeInMills()) / 1000;

PeriodicWorkRequest workRequest =
                new PeriodicWorkRequest.Builder(WorkerClass.class, interval, TimeUnit.SECONDS)
                        .setConstraints(workRequestConstraints)
                        .setInputData(inputData)
                        .addTag(TAG_TASK)
                        .setInitialDelay(initialDelayInSeconds, TimeUnit.SECONDS)
                        .build();

Upvotes: 2

Anjal Saneen
Anjal Saneen

Reputation: 3219

In the new version of Work manager (Version 2.1.0-alpha02 released on May 16, 2019) PeriodicWorkRequests now support initial delays. You can use the setInitialDelay method on PeriodicWorkRequest.Builder to set an initial delay.

PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
        WorkerReminderPeriodic.class,
        24,
        TimeUnit.HOURS,
        PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS,
        TimeUnit.MILLISECONDS)
    .setInitialDelay(1, TimeUnit.HOURS)
    .addTag("send_reminder_periodic")
    .build();


WorkManager.getInstance()
        .enqueueUniquePeriodicWork("send_reminder_periodic", ExistingPeriodicWorkPolicy.REPLACE, workRequest);

Upvotes: 1

Related Questions