What happens with running timers when a system time is changed?
I have an android application and I use handler.postDelayed(Runnable,interval) to post a Runnable to be called (the run() method) at the end of the interval.
The question I have is:
What happens if the underlying system time is changed externally?
My impression is that the posting still happens but at the time of system time change the countdown starts again... Can anybody shade some light here?
Does the behavior change if the time change is forwards or backwards?
First,you should know Handler is based on SystemClock.uptimeMillis().
Handlers sendMessageXXX() methods such as sendMessageDelayedăsendEmptyMessage all use the method below internal:
//calcute the milliseconds we hope to handle the message since the system was booted
sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
Then,the time interval value SystemClock.uptimeMillis() + delayMillis will be kept into Message's field when,and we put the message into the MessageQueue waiting for Looper to poll out it.
While the looper gets the next message from the queue,it will compare SystemClock.uptimeMillis() with msg.when to judge whether the message is ready.If the next message isnt ready,it will set a timeout to wake up until the msg is ready.
Second,you confuse SystemClock.uptimeMillis() with System.currentTimeMillis().Below is part of the documentation of SystemClock which explains the two concepts:
SystemClock.uptimeMillis() is counted in milliseconds since the system was booted. This clock stops when the system enters deep sleep (CPU off, display dark, device waiting for external input), but is not affected by clock scaling, idle, or other power saving mechanisms. This is the basis for most interval timing such as Thread.sleep(millls), Object.wait(millis), and System.nanoTime(). This clock is guaranteed to be monotonic, and is suitable for interval timing when the interval does not span device sleep.
System.currentTimeMillis() is the standard "wall" clock (time and date) expressing milliseconds since the epoch. The wall clock can be set by the user or the phone network (see setCurrentTimeMillis(long)), so the time may jump backwards or forwards unpredictably. This clock should only be used when correspondence with real-world dates and times is important, such as in a calendar or alarm clock application. Interval or elapsed time measurements should use a different clock. If you are using System.currentTimeMillis(), consider listening to the ACTION_TIME_TICK, ACTION_TIME_CHANGED and ACTION_TIMEZONE_CHANGED Intent broadcasts to find out when the time changes.
No it doesn't matter. If you dig around the code, the delay is provided by the following mechanism -
SystemClock.uptimeMillis() + delayMillis
So it is purely relative. And changing of system time has no effect on it
Related
I have a group of components connected and placed in a distributed system. AN events gets injected into the starting components and gets passed through all components which are placed in different region containers and under different time zone. I want to capture time lag of
this event from the time of it being passed entering into the first component to going out from the last component and being notified to the subscribed client. Note, There should not be any negative time difference coming while measuring the lag when event flows from one component to other wherein bot two components are in different time zones.This is a strictly distributed system here.
Simply by getting the time difference to a fixed point.
Calendar.getInstance().getTimeInMillis() returns the ms to the 1.1.1970 UTC.
If you save the millseconds right before you begin your execution chain and compare (subtract the start time from the end time) that value is the elapsed time in ms.
I'm working on a CountDown app. I want to launch a 'end of countdown activity' when the countdown reaches 0. I have a variable keeping track of how much time is left (variable that I use to display the countdown).
The documentation gives me this (I have to use this method because it's part of the exercise):
public void setExact (int type,long triggerAtMillis,PendingIntent operation)
Knowing this I pass my countdown variable as the second argument thinking the activity would roughly be opened around the time I've given.
Let's say, I put a duration of 30s in the duration variable. I start the countdown by pushing a button and I use the 'setExact' method using the duration variable.
Even though, I pass 30s (obviously converted in millis), the 'end of countdown activity' launches only after 5s.
Feel free to download the project.
It sounds like you might be passing in 30000 for the trigger time, when it should probably be 30000 plus the current time in ms.
From the documentation:
triggerAtMillis long: time in milliseconds that the alarm should go off, using the appropriate clock (depending on the alarm type).
I have a piece of code that has to be executed at a particular time every day. If I schedule it to be executed at 9PM everyday, then it has to work even during the switching of Day light saving.
Which Java API can be used to achieve this?
int ONE_DAY = 1000 * 60 * 60 * 24;
Timer timer = new Timer();
timer.schedule(myTimerTask, startTime, ONE_DAY); // startTime is 9PM of current day
I've used the above approach which will not take care of DST.
If you need to schedule based on calendrical values - rather than just elapsed time, basically - then you either need to wrap Timer in your own code, or use a library which has already been built for this purpose. In this case, I suspect the Quartz Scheduler is your best bet.
Given how complicated date/time can be, I'd generally recommend using a well-known library over rolling your own code. Note that this often doesn't mean that you can get away without thinking about complicated aspects of the problem - it just means that you should be able to express your requirements fairly simply. For example, in the context you're looking at, you should consider:
What time zone do you want the "9pm" to be expressed in? Is it the system default time zone? Some other specific one? Multiple different time zones for different tasks?
What do you want to happen if the scheduled time doesn't occur, or occurs twice on one day? You're likely to be okay with 9pm, but if you had (say) 1.30am in the UK time zone, when the clocks go forward into BST, that will be skipped for that day - and when the clocks go back into GMT, it will occur twice.
How do you want to handle the system clock being changed, either manually or automatically?
You can schedule the timer to run the task each hour and let the task decide when to actually run using Calendar
I have a independent clock created in my application. The clock runs as a different thread in the activity, starting from a base time set by me. I update the clock using the difference between the uptimemillis when I set the clock, and the current uptimemillis. But the uptimetimer, can be reset by Android, and is ever reset when Android reboot.
I only want to know if the uptime timer is reset, to know if the clock is still reliable.
How?
According to the documentation you can use SystemClock.elapsedRealtime()
elapsedRealtime():
Returns milliseconds since boot, including time spent in sleep.
This value will only be reset when the device is restarted. Listen to the broadcast boot_complete and you will know when that is.
The problem with the updateMillis() is clearly noted in the documentation:
uptimeMillis():
Returns milliseconds since boot, not counting time spent in deep sleep. Note: This value may get reset occasionally (before it would otherwise wrap around).
From how I understand the documentation, by using elapsedRealtime your users cannot manipulate your counter.
Said now is 6 o'clock, I have a Timer and scheduled a TimerTask at 10 o'clock. After that, System DateTime is adjusted by an other service (ntp for example) to 9 o'clock. I still want my TimerTask will be fired at 10 o'clock but it does not, Timer still wait for next 4 hours and fire my TimerTask. What should I do in this situation?
Firstly, you're already in a pretty nasty mess if your clock is out by 4 hours. Typically time adjustments will only be by milliseconds or seconds - or occasionally a minute or two, if the machine hasn't been online for a very long time. One option would be to check that the time is reasonably accurate by making your own NTP call before setting the timer.
Another option is to make a reasonably regularly-invoked timer - for example once every minute or five minutes - which checks the time and then optionally takes action. It's slightly less efficient, but I wouldn't expect the impact of waking up a single thread to perform a simple check once a minute or so would have a significant effect on performance. You should adjust the regularity of the check based on how accurately you need your timer to fire, and how little performance impact you need it to have.