Execute task every second using Work Manager API
Asked Answered
H

4

39

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)
Houser answered 6/7, 2018 at 4:9 Comment(5)
it work only one time when application start. but what I want is I want it to execute every second bro.Houser
@VicJordan: you got it?Houser
I guess the minimum time interval (and default time interval) is 15 minutes. Moreover it is not advised to run bg task every second as it may not be battery efficient.Marin
You're right bro. After trying to research more about it and I got the answer.Houser
guys can you look at my question ? please :)Elude
R
58

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.

Rafaelarafaelia answered 6/7, 2018 at 5:56 Comment(6)
I got it. Anyway it should show as warning message to let us know about it.Houser
@Houser yeah! It does explicitly specifies in the document though.Rafaelarafaelia
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.Houser
@Houser no problem. Remember to mark answer as accepted if it was useful, so that others can benefit too and enjoy coding :-)Rafaelarafaelia
> "avoid scheduling work so frequently". Can you give a alternative solution if performing a task every second is a requirement?Gastronomy
hey @JesperHustad did you find any solution or workaround? I have a similar requirement.Warmth
L
13

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();
    }
}

Liriodendron answered 27/11, 2021 at 11:57 Comment(2)
In this way, it always work. Do not forget to put a counter to stop it.Levis
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.Bezique
G
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.

Goatsbeard answered 26/8, 2019 at 13:57 Comment(0)
P
9

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.

Poe answered 15/11, 2021 at 7:19 Comment(2)
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()?Epitomize
@Epitomize 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.Poe

© 2022 - 2024 — McMap. All rights reserved.