Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change periodic work request period without it running immediately using WorkManager?

val request = PeriodicWorkRequestBuilder<FooWorker>(1, TimeUnit.DAYS).build()
WorkManager.getInstance().enqueueUniquePeriodicWork(
    "FOO",
    ExistingPeriodicWorkPolicy.REPLACE,
    request
)

The code above is ran in onCreate of Application to ensure the request is enqueued. However, this will cause a problem where the FooWorker will run every time user start the application because ExistingPeriodicWorkPolicy.REPLACE cancel previous work and enqueue new work which cause it run immediately.

If we change to ExistingPeriodicWorkPolicy.KEEP, we will not able to replace the work even the period or the worker is changed.

Is there a way to replace the request after the current one is running?

For example, origin request run a 1 time per day and the new request is 1 time per hour. After the next origin request is ran, then replace it with new request.

like image 924
Joshua Avatar asked Oct 10 '18 03:10

Joshua


People also ask

Which api do you use to add constraints to a WorkRequest?

To create a set of constraints and associate it with some work, create a Constraints instance using the Contraints. Builder() and assign it to your WorkRequest. Builder() .

How do I cancel a periodic request?

Stop a running Worker You explicitly asked for it to be cancelled (by calling WorkManager. cancelWorkById(UUID) , for example). In the case of unique work, you explicitly enqueued a new WorkRequest with an ExistingWorkPolicy of REPLACE . The old WorkRequest is immediately considered cancelled.

Does WorkManager work in doze mode?

Another nice feature of WorkManager is that it respects power-management features so that if a job is scheduled to run at a defined time and the device is in Doze at that time, WorkManager will try to run the task during a maintenance window if the constraints are met or after Doze is lifted.

What is periodic work?

↳ androidx.work.PeriodicWorkRequest. A WorkRequest for repeating work. This work executes multiple times until it is cancelled, with the first execution happening immediately or as soon as the given Constraints are met.


3 Answers

There is no way to do exactly what you want with periodic work in a clean way.

However, there's absolutely no need to use periodic work itself. The same structure can be easily accomplished by scheduling the next WorkRequest at the end of your doWork method, right before returning Result.SUCCESS:

fun doWork(): Result {
  reallyDoWork()
  // Now schedule the next "periodic" work
  val request = OneTimeWorkRequestBuilder<FooWorker>().build()
  WorkManager.getInstance().enqueueUniqueWork(
    "FOO",
    ExistingWorkPolicy.REPLACE,
    request
  )
  return Result.SUCCESS
}

With this setup, your onCreate() of Application can safely use ExistingWorkPolicy.KEEP to avoid rescheduling work if you already have a WorkRequest queued up and when that queued up work fires, the next WorkRequest will be queued up with the appropriate new period.

like image 142
ianhanniballake Avatar answered Oct 01 '22 13:10

ianhanniballake


Looks like there is a way to replace a periodic work now with enqueueUniquePeriodicWork.

  val request = PeriodicWorkRequest.Builder(FooWorker::class.java, 1, TimeUnit.DAYS).build()
  WorkManager.getInstance(appContext)
  .enqueueUniquePeriodicWork(WORK_TAG, ExistingPeriodicWorkPolicy.REPLACE, request)

Make sure you are passing ExistingPeriodicWorkPolicy instead of ExistingWorkPolicy

like image 20
meh Avatar answered Oct 01 '22 12:10

meh


If you want to use ExistingPeriodicWorkPolicy.KEEP and to update PeriodicWorkRequest only when you want to change repeat interval, there is no solution from WorkManager, but you can save interval in sharedPreferences and check if interval was changed. And based on that to use ExistingPeriodicWorkPolicy.KEEP or ExistingPeriodicWorkPolicy.REPLACE

public static void enqueue(Context context) {
        Log.d(TAG, "enqueue()");
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
        int repeatInterval = sharedPreferences.getInt("REPEAT_INTERVAL_HOURS", 0);

        PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest
            .Builder(FooWorker.class, REPEAT_INTERVAL_HOURS, TimeUnit.HOURS)
            .build();

        ExistingPeriodicWorkPolicy policy = repeatInterval == REPEAT_INTERVAL_HOURS ? ExistingPeriodicWorkPolicy.KEEP : ExistingPeriodicWorkPolicy.REPLACE;

        sharedPreferences.edit().putInt("REPEAT_INTERVAL_HOURS", REPEAT_INTERVAL_HOURS).apply();

        WorkManager.getInstance(context).enqueueUniquePeriodicWork("fileRemove", policy, periodicWorkRequest);
    }
like image 45
Šemsudin Tafilović Avatar answered Oct 01 '22 11:10

Šemsudin Tafilović