Search code examples
androidrunnablepostdelayed

Running a task at a specific time using postDelayed


I would like to start a task at a specific time. For that I use runnable and postDelayed method as follows:

private Runnable mLaunchTask = new Runnable() {
        public void run() {

            try {
                MY TASK
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
};

In my code I use mLunchTask as follows:

mHandler = new Handler();
mHandler.postDelayed(mLaunchTask, myDelay*1000); 

and myDelay is computed as follows:

s  = DateFormat.format("hh:mm:ss aaa", d.getTime());
cTime = s.toString(); // current Time
ch = Integer.parseInt(cTime.substring(0,2)); // current hour
cm = Integer.parseInt(cTime.substring(3,5)); // current minute
cs = Integer.parseInt(cTime.substring(6,8)); // current second
if (cTime.substring(9,11).equalsIgnoreCase("pm") && (ch<12) ) ch = ch+12; 
myDelay=(desiredHour-ch)*3600+(desiredMinute-cm)*60 - cs;
if (myDelay<0) myDelay = 0;

and desiredHour and desiredMinute are set by user. The expectation is that MY TASK starts at desiredHour and desiredMinute and 0 seconds. However "MY TASK starts with a few seconds delay, which looks like is random.

Based on the above code, is there any reason that it does not start at the exact desired time?

Thanks


Solution

  • First of all, your delay calculation is correct, but the "pm" detection doesn't work with other languages. It is much better to use the calendar to get the delay:

    Calendar calendar = Calendar.getInstance();
    long currentTimestamp = calendar.getTimeInMillis();
    calendar.set(Calendar.HOUR_OF_DAY, desiredHour);
    calendar.set(Calendar.MINUTE, desiredMinute);
    calendar.set(Calendar.SECOND, 0);
    long diffTimestamp = calendar.getTimeInMillis() - currentTimestamp;
    long myDelay = (diffTimestamp < 0 ? 0 : diffTimestamp);
    

    Now you have the delay in milli secs and can start the handler:

    new Handler().postDelayed(mLaunchTask, myDelay);
    

    In my test the following runnable logs at the desired time with no delay.

    private Runnable mLaunchTask = new Runnable() {
        public void run() {
            Calendar calendar = Calendar.getInstance();
            Log.d("test", "started at " 
                + calendar.get(Calendar.HOUR_OF_DAY) + " " 
                + calendar.get(Calendar.MINUTE) + " "
                + calendar.get(Calendar.SECOND)
            );
        }
    };
    

    Maybe your started task needs some seconds to be loaded?

    Could the AlarmManager be an alternative?