Repeat a task within a duration with delay

android repeat task periodically
android repeat task every second
android call method every 10 seconds
android handler
postdelayed
call method every 5 minutes android
android handler periodic task
android run task every minute

I have to move a progress bar within a time frame, for example within 6s. I am using coroutines and the "repeat" function. The code executes except that the total execution time is not as specified. Below is my code.

val progressJob = Job()
var startTime = 0L
CoroutineScope(Dispatchers.Default + progressJob).launch {
    startTime = System.currentTimeMillis()
    repeat(1000) {
        progressBar.progress += 1
        delay(6)
    }
    Log.d(TAG, "total time= ${System.currentTimeMillis() - startTime}")
}

I am expecting "total time" would be 6000, but I am getting values greater than 6000 by at least 500.

Basically I just want to repeatedly increment the progress bar within a time frame, and I am not using animation because of performance issue.

Is there anything I am missing?

so what you are doing here is simulating progress. Ideally, there would be some way of checking the actual progress of your bar, and updating it, and when it is done, ending. But, if this is not possible, then ya, simulation is your choice.

So, with coroutines we are dealing with a threaded environment, and within that, we have our coroutines which need to be continued when the hand over control of execution. In your implementation, this happens at the delay call. For this reason, it is very difficult to guarantee that your coroutine will complete in your desired time. All delay can do is say that it will not resume before "at least" the specified time has elapsed, and probably quite often, more time would have elapsed, not the exact time.

So, how do we get this to execute in as close to your desired time frame as possible? What we need to do is drop the repeat, and rather check on the elapsed time to decide if we finish. Here is a rough implementation that will hopefully help.

class Bar(val barLength: Int = 1000) {
    var progress = 0
}

suspend fun simulateProgress(bar: Bar, job: Job, totalDurationMillis: Long, incrementsMills: Long): Job {
    var startTime = System.currentTimeMillis()
    return CoroutineScope(Dispatchers.Default + job).launch {
        var totalElapsed = 0L
        while (totalElapsed < totalDurationMillis) {
            totalElapsed = System.currentTimeMillis() - startTime
            val progressRatio = totalElapsed.toDouble()/totalDurationMillis.toDouble()
            bar.progress = (progressRatio * bar.barLength.toDouble()).toInt()
            delay(incrementsMills)
        }
        println("Elapsed: $totalElapsed, Progress: ${bar.progress}")
    }
}

fun main() = runBlocking {
    val job = Job()
    val bar = Bar()
    val progressJob = simulateProgress(bar, job, 6000, 10)
    progressJob.join()
} 

Repeat a task within a duration with delay, so what you are doing here is simulating progress. Ideally, there would be some way of checking the actual progress of your bar, and updating� If you register a task that contains a trigger with a repetition interval equal to one minute and a repetition duration equal to four minutes, the task will be started five times. The five repetitions can be defined by the following pattern: A task starts at the beginning of the first minute. The next task starts at the end of the first minute.

Coroutine does not provide precise timing. If the processor is busy running other stuff at the same time, coroutines can be easily delayed. Use the Timer Class for precise timing. Here is an example. I log the time every seconds and cancel the timer after 6 seconds. The results are only off by a few milliseconds.

    var startTime = 0L
    val timer : Timer = Timer()
    val task = object : TimerTask()
    {
        var lastTime = 0L
        override fun run() {
            val now = System.currentTimeMillis()
            if(now/1000 > lastTime/1000 )
            {
                Log.d("timer","total time= ${now - startTime}")
                lastTime = now
            }
            if(now - startTime >= 6000)
            {
                timer.cancel()
            }
    }
    startTime = System.currentTimeMillis()
    timer.scheduleAtFixedRate(task,0,6)

Repeating Periodic Tasks, Repeating periodic tasks within an application is a common requirement. Using a Handler , we can execute arbitrary code a single time after a specified delay: We can use a Handler to run code on a given thread after a delay or repeat tasks periodically on a thread. This is done by constructing a Handler and then "posting" Runnable code to the event message queue on the thread to be processed. Executing Code After Delay. Using a Handler, we can execute arbitrary code a single time after a specified delay:

Your are not only measuring the delay of 6 milli seconds but also the time needed to execute the for loop (hidden in repeat), plus the time of progressBar.progress += 1 and the cost of delay itself.

For example:

CoroutineScope(Dispatchers.Default + progressJob).launch {
    startTime = System.currentTimeMillis()
    repeat(1000){
        delay(6)
    }
    val endTime = System.currentTimeMillis() - startTime
    println("total time= $endTime")
}

needs 6751ms (avg. of 100 runs) on my machine.

If I use Thread.sleep instead of delay:

CoroutineScope(Dispatchers.Default + progressJob).launch {
    startTime = System.currentTimeMillis()
    repeat(1){
        delay(6)
    }
    val endTime = System.currentTimeMillis() - startTime
    println("total time= $endTime")
}

it takes 6701ms.

If I execute repeat only once:

CoroutineScope(Dispatchers.Default + progressJob).launch {
    startTime = System.currentTimeMillis()
    repeat(1){
        Thread.sleep(6)
    }
    val endTime = System.currentTimeMillis() - startTime
    println("total time= $endTime")
}

8ms

If I remove repeat:

CoroutineScope(Dispatchers.Default + progressJob).launch {
    startTime = System.currentTimeMillis()         
    Thread.sleep(6)
    val endTime = System.currentTimeMillis() - startTime
    println("total time= $endTime")
}

Multiple ways to schedule repeated tasks in android, This kind of delay in execution mainly come from two sources. The first is so- called time drift. When the screen is on, and the phone is fully awake,� Examples. The following example launches a task that includes a call to the Delay(TimeSpan, CancellationToken) method with a 1.5 second delay. Before the delay interval elapses, the token is cancelled.

I would do it with something like this:

withTimeout(1300L) {
    repeat(1000) { i ->
        println("Blip Blop $i ...")
        delay(500L)
    }
}

For more examples see official doc: https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html

How to schedule tasks in Java to run for repeated fixed-delay , One of the methods in the Timer class is the void schedule(TimerTask task, long delay, long period) method. This method schedules tasks for� To Change Keyboard Repeat Delay and Rate in Windows 10, Open the classic Control Panel app. Switch its view to either "Large icons" or "Small icons" as shown below. Click on the Keyboard applet. In the keyboard dialog, change the position of the Repeat delay slider on the Speed tab to set a longer or shorter delay. Now, change the Repeat rate slider value to be slow or fast for what you want. Click on the Apply button.

Java, Schedule a delayed one time task, a daily task or just repeat on an Timer and TimerTask are java util classes used to schedule tasks in a� Yes, my goal is to repeat the steps within "Do Until" until the task item is marked as completed. So, if the Timeout value just limits the duration of each iteration of the Do Until, I'm guessing I would need to add a Delay if I want each iteration to run on a set interval. I will try that. Thanks again for taking the time to help.

Repeat a task with a time delay?, How to repeat a task after a fixed amount of time in android?, I want to a task with a time delay?, Handler(); private Runnable repeatativeTaskRunnable = new � The real delay between func calls for setInterval is less than in the code! That’s normal, because the time taken by func's execution “consumes” a part of the interval. It is possible that func's execution turns out to be longer than we expected and takes more than 100ms.

Using the Timer and TimerTask Classes, class in the java.util package schedules instances of a class called TimerTask � ( in the API is an example of using a timer to perform a task after a delay: you first see this: Task scheduled. Five seconds later, you see this: Time's up! Here are all the Timer methods you can use to schedule repeated executions of tasks:. How To Change The Keyboard Repeat Rate And Repeat Delay In Windows 10:- Open any of the text editors, like notepad, in your Windows PC. Hold down a key for some seconds. You can see that after the first character is typed in, there is a delay before the second one appears. This delay is known as the Keyboard Repeat Delay.

Comments
  • Dropping the repeat and replace with while is the key. On average the total time is 601X, which is close enough for my use case. Thanks a lot.
  • @HaytonLeung - no problem.
  • For some other requirements I will have to stick with coroutines, but thanks for your suggestion.
  • Thank you for your explanation. I didn't notice the for loop inside delay until you point it out. I guess this is where the extra time comes from
  • Just for info - you should not use Thread tools when you are achieving concurrency with coroutines. It sort of defeats the whole point.