Running Task Periodicaly(Once a Day/Once a Week)

Running task periodicaly(once a day/once a week)

Yes it is, you need to look at the AlarmManager to setup a reoccurring "Alarm". This is better for battery life on the device, as unlike a service it does not run constantly in the background. The Alarm triggers a broadcast receiver which will execute your custom code.

As a final note - there are enum values for the timing of the Alarm including daily, half daily and many more although you can just set an actual value.

A good example can be found in the follow SO post:

Alarm Manager Example

Update

Newer features have been added to Android. If you are reading this then I would advise you now look into GcmNetworkManager. This optimises battery life and works pre-lollipop. For Lollipop onwards you can use JobScheduler. I would advise using these classes over the AlarmManager.

How to run certain task every day at a particular time using ScheduledExecutorService?

As with the present java SE 8 release with it's excellent date time API with java.time these kind of calculation can be done more easily instead of using java.util.Calendar and java.util.Date.

  • Use date time class's i.e. LocalDateTime of this new API
  • Use ZonedDateTime class to handle Time Zone specific calculation including Daylight Saving issues. You will find tutorial and example here.

Now as a sample example for scheduling a task with your use case:

ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/Los_Angeles"));
ZonedDateTime nextRun = now.withHour(5).withMinute(0).withSecond(0);
if(now.compareTo(nextRun) > 0)
nextRun = nextRun.plusDays(1);

Duration duration = Duration.between(now, nextRun);
long initialDelay = duration.getSeconds();

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(new MyRunnableTask(),
initialDelay,
TimeUnit.DAYS.toSeconds(1),
TimeUnit.SECONDS);

The initialDelay is computed to ask the scheduler to delay the execution in TimeUnit.SECONDS. Time difference issues with unit milliseconds and below seems to be negligible for this use case. But you can still make use of duration.toMillis() and TimeUnit.MILLISECONDS for handling the scheduling computaions in milliseconds.

And also TimerTask is better for this or ScheduledExecutorService?

NO: ScheduledExecutorService seemingly better than TimerTask. StackOverflow has already an answer for you.

From @PaddyD,

You still have the issue whereby you need to restart this twice a year
if you want it to run at the right local time. scheduleAtFixedRate
won't cut it unless you are happy with the same UTC time all year.

As it is true and @PaddyD already has given a workaround(+1 to him), I am providing a working example with Java8 date time API with ScheduledExecutorService. Using daemon thread is dangerous

class MyTaskExecutor
{
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
MyTask myTask;
volatile boolean isStopIssued;

public MyTaskExecutor(MyTask myTask$)
{
myTask = myTask$;

}

public void startExecutionAt(int targetHour, int targetMin, int targetSec)
{
Runnable taskWrapper = new Runnable(){

@Override
public void run()
{
myTask.execute();
startExecutionAt(targetHour, targetMin, targetSec);
}

};
long delay = computeNextDelay(targetHour, targetMin, targetSec);
executorService.schedule(taskWrapper, delay, TimeUnit.SECONDS);
}

private long computeNextDelay(int targetHour, int targetMin, int targetSec)
{
LocalDateTime localNow = LocalDateTime.now();
ZoneId currentZone = ZoneId.systemDefault();
ZonedDateTime zonedNow = ZonedDateTime.of(localNow, currentZone);
ZonedDateTime zonedNextTarget = zonedNow.withHour(targetHour).withMinute(targetMin).withSecond(targetSec);
if(zonedNow.compareTo(zonedNextTarget) > 0)
zonedNextTarget = zonedNextTarget.plusDays(1);

Duration duration = Duration.between(zonedNow, zonedNextTarget);
return duration.getSeconds();
}

public void stop()
{
executorService.shutdown();
try {
executorService.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException ex) {
Logger.getLogger(MyTaskExecutor.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

Note:

  • MyTask is an interface with function execute.
  • While stopping ScheduledExecutorService, Always use awaitTermination after invoking shutdown on it: There's always a likelihood your task is stuck / deadlocking and the user would wait forever.

The previous example I gave with Calender was just an idea which I did mention, I avoided exact time calculation and Daylight saving issues. Updated the solution on per the complain of @PaddyD

iOS Run Code Once a Day

Here's the situation regarding background execution and notifications and timers etc. in relation to an app scheduling some activity to happen periodically.

  1. An app cannot execute in the background unless:

    1. It requests extra time from the OS to do so. This is done using beginBackgroundTaskWithExpirationHandler. It is not specified (intentionally) by Apple how long this extra time is, however in practice it is around 10 minutes.

    2. An app has a background mode, the modes are: voip, audio, location, newstand. Even if it has one of these types an app cannot execute without some restrictions. The rest of this discussion assumes the app does not have a background mode.

  2. When an app is suspended it cannot do ANYTHING to rouse itself directly. It cannot previously have scheduled an NSTimer, it cannot make use of something like performSelector:afterDelay. etc.

    The ONLY way the app can become active again is if the USER does something to make it active. The user can do this from via of the following:

    1. Launch the app directly from its icon

    2. Launch the app in response to a local notification that was previously scheduled by the app while it was active.

    3. Launch the app in response to a remote notification sent by a server.

    4. A few others: such as URL launching if the app is registered to deal with launching via a url; or if its registered to be capable of dealing with a certain type of content.

If an app is in the foreground when a local/remote notification fires then the app receives it directly.

If the app is not currently in the foreground when a local/remote notification fires then the app DOES NOT receive it. There is no code that is executed when the notification fires!

Only IF the user selects the notification will the app become active and it can execute.

Note that the user can disable notifications, either for the entire device, or just for a specific application, in which case the user will never see them. If the device is turned off when a notification is due to fire then it is lost.

Is it possible to run a daily task on android without openning the app?

Unless your app has been force closed, any job scheduled with job scheduler will run even if the app is terminated. If needed it will be restarted. The only thing that will prevent it is if you declare the job not persistent and reboot the device.

Spring scheduling task - run only once

You can use one of Spring's TaskScheduler's implementations. I provided an example below with one which does not require too much configuration (ConcurrentTaskScheduler that wraps a single-threaded scheduled executor).

The simplest method is the one named schedule that takes a Runnable
and Date only. That will cause the task to run once after the
specified time. All of the other methods are capable of scheduling
tasks to run repeatedly.

Read more on task execution & scheduling

Simple working example:

private TaskScheduler scheduler;

Runnable exampleRunnable = new Runnable(){
@Override
public void run() {
System.out.println("Works");
}
};

@Async
public void executeTaskT() {
ScheduledExecutorService localExecutor = Executors.newSingleThreadScheduledExecutor();
scheduler = new ConcurrentTaskScheduler(localExecutor);

scheduler.schedule(exampleRunnable,
new Date(1432152000000L));//today at 8 pm UTC - replace it with any timestamp in miliseconds to text
}

...

executeTaskT() //call it somewhere after the spring application has been configured

Note:

To enable support for @Scheduled and @Async annotations add
@EnableScheduling and @EnableAsync to one of your @Configuration
classes


Update - cancelling the scheduled task

TaskScheduler's schedule method returns a ScheduledFuture which is a delayed result-bearing action that can be cancelled.

So in order to cancel it, you need to keep a handle to the scheduled task (i.e. keep the ScheduledFuture return object).

Changes to the code above for cancelling the task :

  1. Declare the ScheduledFuture outside your executeTaskT method.
    private ScheduledFuture scheduledFuture;

  1. Modify your call to schedule to keep the return object as such:
    scheduledFuture = scheduler.schedule(exampleRunnable,
new Date(1432152000000L));

  1. Call cancel on the scheduledFuture object somewhere in your code
    boolean mayInterruptIfRunning = true;
scheduledFuture.cancel(mayInterruptIfRunning);

Celerybeat schedule executing task multiple times?

This may make more sense if you consider what crontab(hour=23, day_of_week='sun') does:

>>> crontab(hour=23, day_of_week='sun')
<crontab: * 23 sun * * (m/h/d/dM/MY)>

So what this means is that the task will execute every minute at 11pm every sunday.

If you want it to execute only at the first minute you can specify:

crontab(minute=0, hour=23, day_of_week='sun')


Related Topics



Leave a reply



Submit