37

Work Manager is a new API and I try to execute task every second, but it doesn't work.

This is my worker class

class TestingWorker : Worker(){
    override fun doWork(): Result {
        Log.i("CheckWorker","Result here")
        return Result.SUCCESS
    }
}

and this is where I called it.

 val recurringWork: PeriodicWorkRequest = PeriodicWorkRequest.Builder(TestingWorker::class.java, 1, TimeUnit.SECONDS).build()
 WorkManager.getInstance()?.enqueue(recurringWork)
Chivorn
  • 2,203
  • 2
  • 21
  • 37

4 Answers4

53

Its not working because, the minimum interval between two periodic work request is 15 min which is defined by MIN_PERIODIC_INTERVAL_MILLIS.

Based on the documentation:

Creates a PeriodicWorkRequest to run periodically once every interval period. The PeriodicWorkRequest is guaranteed to run exactly one time during this interval. The intervalMillis must be greater than or equal to PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS. It may run immediately, at the end of the period, or any time in between so long as the other conditions are satisfied at the time.

I would recommend you to avoid scheduling work so frequently. This will end up in consuming more resources and eventually impacting the battery life.

Sagar
  • 23,903
  • 4
  • 62
  • 62
  • 4
    I got it. Anyway it should show as warning message to let us know about it. – Chivorn Jul 06 '18 at 06:20
  • @Chivorn yeah! It does explicitly specifies in the document though. – Sagar Jul 06 '18 at 06:26
  • 3
    I've checked in source code and I found as bellow: public void setPeriodic(long intervalDuration) { if (intervalDuration < MIN_PERIODIC_INTERVAL_MILLIS) { Log.w(TAG, String.format( "Interval duration lesser than minimum allowed value; Changed to %s", MIN_PERIODIC_INTERVAL_MILLIS)); intervalDuration = MIN_PERIODIC_INTERVAL_MILLIS; } setPeriodic(intervalDuration, intervalDuration); } So we cannot do it less than 15 mn. Thanks bro. – Chivorn Jul 06 '18 at 06:46
  • @Chivorn no problem. Remember to mark answer as accepted if it was useful, so that others can benefit too and enjoy coding :-) – Sagar Jul 06 '18 at 06:46
  • > "avoid scheduling work so frequently". Can you give a alternative solution if performing a task every second is a requirement? – Jesper Hustad Feb 16 '23 at 00:07
12

Another way to acheieve the behaviour is to create OneTimeWorkRequest and that worker request, schedule another one for the interval you want with an initial delay

setInitialDelay(5, TimeUnit.MINUTES)

e.g.

public class UploadWorker extends Worker {
    private final Context context;

    public UploadWorker(
            @NonNull Context context,
            @NonNull WorkerParameters params) {
        super(context, params);
        this.context = context;
    }

    @Override
    public Result doWork() {

        Log.i("tracer:", "Worker executed");
        // Indicate whether the work finished successfully with the Result
        OneTimeWorkRequest mywork = new OneTimeWorkRequest.Builder(UploadWorker.class)
                .setInitialDelay(5, TimeUnit.MINUTES)
                .build();
        WorkManager.getInstance(this.context).enqueue(mywork);
        return Result.success();
    }
}

Talha Junaid
  • 2,351
  • 20
  • 29
  • 1
    In this way, it always work. Do not forget to put a counter to stop it. – canerkaseler Jun 08 '22 at 22:15
  • Good try, but it doesn't work, The moment the app goes into background, the worker no longer fires. There is also the new `setExpedited` builder option, but is not compatible with `setInitialDelay`. – Mister Smith Jul 21 '22 at 19:06
9

WorkManager is not designed to run tasks every second, as it has two options to build work request that is and

  • PeriodicWorkRequest - runs repeated task every 15 mins, even if we change the time interval to anyhwere < 15 mins it will by default run for 15 mins only.
  • OneTimeWorkRequest - runs once

WorkManager will enqueues the workrequests will call the respectively Worker classes to run the task where each workerclass overrides doWork() where the actual task is defined.

This method runs in background thread and runs for 10mins after which the worker stops.

Therefore if you want to schedule tasks running every second better the run foreground service or if your having running tasks in short duration.

If you want to run background tasks for longer periods, best practice is to avoid it.

Ajay Deepak
  • 471
  • 5
  • 9
7

It is being so late for the answer but, work manager is useful to schedule task for periodic time for at least 15 min delay in between periodic request but somehow if you wants to achieve periodic work then you can do this with the login given below which is not a good practice but it works.

You can set worker for periodic request with 15 minutes request which will work periodically and in the worker class you can manage your worker for every second as given below.

override suspend fun doWork(): Result {
    for (i in 1..900){
        delay(1000)
        Log.d("Work for every second", "doWork: Running")
    }
    return Result.success()
}

This will work every second for 15 minutes and after 15 minutes your worker will again make a request so this is how you can achieve work for every second. You have to manage your worker to when to stop else this will create memory leaks too. This is not a best practice to work this kind of functionality for every second but this is how you can achieve this.

Khush Parmar
  • 316
  • 2
  • 9
  • Interesting. I think this would need to be in a subclass of `CoroutineWorker` (not regular synchronous `Worker`) for `doWork` to allow `suspend`, and should be called with `setForeground()`? – user56reinstatemonica8 Jan 01 '23 at 23:40
  • @user56reinstatemonica8 Yes suspend functions are allowed to invoked from the background threading functionality hence coroutine workers are used to invoke suspend functions like using lifecycle scope in io dispatcher. About setForeground() you can switch the thread of the scope or either use with it as you mentioned. – Khush Parmar Jan 07 '23 at 06:34