Doing a countdown properly - android

Each second that != the previous second a new value is posted and when the value reaches <1 the countdown finishes.
I note the starting time with System.currentTimeMillis() and simply calculate the remainder of the countdown from there. All this is done in a runnable which gets re-run over and over.
When typing out the min & seconds left I use this formula:
secondsLeft= (int) ((time / 1000) % 60);
minutesLeft = (int) (time / (60*1000));
The problem Im getting at is that when the secondsLeft reaches <1 the timer finishes. But my Alarm set through AlarmManager which uses pure millis and thus not rounding to nearest second, gets run a little sooner , or later than the timer finishes.
What can I do to make them synchronized?
Some extra info:
I am vibrating the phone when the countdown finishes. Hence I cant have the timer reach 0 and then the phone vibrating sooner/later.
I use AlarmManager for the vibrate as it wont go off if phone is asleep too long (service running in foreground works most of the time,but not 100%).

By your description, I believe you're getting bit by rounding. If you start the timer at, say, 1380866264454ms, next second by your algorithm happens in only 546 milliseconds, not 1000 - so your countdown would end approximately 454ms before your alarm is scheduled. Thus, get the last three digits of your start time and subtract them from the current time before you do the calculation you show in the post. The first change after (1380866264454 - 454) will be at (1380866265454 - 454), at least 1000ms away.

Related

How do I start chronometer with a specific starting time?

Let's say I have this variable:
long myMillis = 20000;
This means that I want my Chronometer to start at exactly 20 seconds (00:20).
I tried doing this:
chronometer.setBase(myMillis);
But it doesn't work. It dosn't start with 20 seconds. It starts with some weird time that doesn't make sense.
In general the chronometer works like this (if you would like to set
the Base to a specific nr):
mChronometer.setBase(SystemClock.elapsedRealtime() - (nr_of_min * 60000 + nr_of_sec * 1000)))
so make it:
mChronometer.setBase(SystemClock.elapsedRealtime() - (2* 60000 + 0 * 1000)))
For Kotlin,
To start Chronometer with starting time 20 seconds, you can use
val timeInMilSeconds = 20000
chronometer.base = SystemClock.elapsedRealtime() - timeInMilSeconds
chronometer.start()
This will start Chronometer with starting time 20 seconds i.e. 00:00:20
Its Late but may help others.
I have used following code in first fragment
chronometerTimer.setBase(SystemClock.elapsedRealtime());
chronometerTimer.start();
and then move on some condition to next fragment where chornometer should start at same time of previous chornometer ends, i get elapsed time using this code.
long elapsedMillis = SystemClock.elapsedRealtime() - chronometerTimer.getBase();
and i send elapsedMilis in next fragment and use following code
chronometerTimer.setBase(SystemClock.elapsedRealtime() - elapsedTime);
chronometerTimer.start();
it worked perfectly.

Accuracy issue in creating a simple StopWatch Timer android app

I'm new to Android development.I want to create a stopwatch with precision of 0.01 seconds.Here is part of my code(which I think the problem lies within):
private void runTimer()
{
final TextView timeView = (TextView) findViewById(R.id.time_view);
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
int seconds = centiseconds / 100;
int centisecs = centiseconds % 100;
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
int secs = seconds % 60;
String time = String.format("%d:%02d:%02d.%02d", hours, minutes, secs, centisecs);
timeView.setText(time);
if (isRunning) {
centiseconds += 1;
}
handler.postDelayed(this, 10);
}
});
}
}
Since postDelayed method's delay is in milliseconds, ten times of it would be 1 centiseconds. So I'm incrementing my centiseconds variable every 10ms.So far so good.
But when I test my app on my device, it seems the seconds are ticking slower than they should. Is is probable that the codes corresponding to division and modulo operations cause so much lag that hinder the increment and reduce the accuracy?
I've rewritten the app for 0.1 seconds(deciseconds) (by: centiseconds / 10 and % 10 and postDelayed(..., 100) ) and it seems it is ticking correctly.
P.S.
Is this the reason my 4.3 Jellybean's Stopwatch has 0.1 seconds accuracy?
What is the limit of precision in android for such app? ( Timely's has 0.01 seconds so I think it is at least 0.01 seconds)
This is wrong approach as you cannot rely on system message queue as source of precise ticks as it does NOT guarantee any precision in delivery. postDelayed() queues your runnable to be delivered no sooner than now + delay but for precise delivery is not quaranteed and additional delays can happen for many reasons which in longer run would give you noticeable cumulative error in measurements.
You can however use postDelayed() to update your UI, but to know how much time passed you should use system clock methods, not own counters.
You also should fire your runnable at least twice per precision, i.e. if you want to update timer display once per minute, you should "tick" twice per minute so if there'd be any delay in message queue handling your UI shall still get at least one tick per second on time.

Android: Chronometer SetBase in minutes

Is there a way by which using the android chronometer class to set base of the chronometer in 15 minutes and from that period the times goes down until 0 seconds?
I have tried with setBase(60000) but this isn't work.
Check out this thread Android: chronometer as a persistent stopwatch. How to set starting time? What is Chronometer "Base"? as well as this thread Android - Get time of chronometer widget. Neither answers your question directly, but the nuggets there should lead you to an answer.
In general the chronometer works like this (if you would like to set the Base to a specific nr):
mChronometer.setBase(SystemClock.elapsedRealtime() - (nr_of_min * 60000 + nr_of_sec * 1000)))
what you are asking can be done through a countdown (http://developer.android.com/reference/android/os/CountDownTimer.html)
Or create your own countdown by using the chronometer like this (more work should be done cause i just wrote this and did not test it yet)
private OnChronometerTickListener countUp = new OnChronometerTickListener(){
#Override
public void onChronometerTick(Chronometer chronometer){
long elapsedTime = (SystemClock.elapsedRealtime() - mChronometerCountUp.getBase()) / 60000;
Log.v("counting up", elapsedTime);
// you will see the time counting up
count_down--;
if(count_down == 0){
mChronometerCountUp.stop();
}
// an int which will count down,
// this is not (very) accurate due to the fact that u r using the update part of the chronometer
// u just might implement the countdown i guess
// or 2 chronometers (one counting up and an other counting down using the elapsed time :p)
// just remember programming is creating ur solution to problems u face its like expression urself
};
};
http://developer.android.com/reference/android/widget/Chronometer.html
For set the base time you can use elapsedRealtime(), and you can output format with setFormat()

System.currentTimeMillis() work wrong

I need stopWatch and I used http://www.goldb.org/stopwatchjava.html
It did not work well so I tried write out the value every 1000ms:
stopWatch.start();
HandlerScrollBar.postDelayed(TtScroll, 1000);
private Runnable TtScroll = new Runnable() {
public void run() {
long time = stopWatch.getElapsedTime();
HandlerScrollBar.postDelayed(TtScroll,(long) 1000);
Log.d(TAG, Long.toString(time));
}
};
I can see value of time every second in CatLog and this is result:
Real time is max +5ms but in Column it is at least +3 seconds! How is it possible? It is the same with
new Date().getTime().
Is there some StopWatch class which will pass this test as expected?
Thank you.
If you are measuring elapsed time, and you want it to be correct, you must use System.nanoTime(). You cannot use System.currentTimeMillis(), unless you don't mind your result being wrong.
The purpose of nanoTime is to measure elapsed time, and the purpose of currentTimeMillis is to measure wall-clock time. You can't use the one for the other purpose. The reason is that no computer's clock is perfect; it always drifts and occasionally needs to be corrected.
Since nanoTime's purpose is to measure elapsed time, it is unaffected by any of these small corrections.I would suggest to pick the nanoTime() as it has better accuracy in those microcalculations.
for extremely precise measurements of elapsed time. From its javadoc:
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;
Seems impossible. I've never had System.currentTimeMillis() act that way. Also, you're logging out as Log.d() but the logcat you show indicates a Log.e(). You sure that's the right logcat?

Android Dev: Timer not honoring dynamic interval period

im working on a audio profile switcher for android and as part of the entire project, i have a service that is running in the background using the following timer code:
timer.scheduleAtFixedRate( new TimerTask() {
public void run() {.....}, 0, nextUpdateInterval);
what im noticing is that the timer is not honoring the dynamically generated next update interval period...the nextUpdateInterval is declared as private static long which is initialized to 30000 (30 seconds) for the first run....then once a profile is found, i do some math and update the nextUpdateInterval...i have converted the nextUpdateInterval value back out to hours/minutes for debugging purpose, and the calculation is working as expected...like it shows me in hours and minutes, when the next timer execution should take place...
nextUpdateInterval calculation: long entirePeriodDiff = toTimeMiliseconds - fromTimeMiliseconds;
then once a profile is found, i calculate the elapsedTime like so: long elapsedTime = rightNowDate.getTime() - fromDate.getTime();
and then i update the nextUpdateInterval: nextUpdateInterval = entirePeriodDiff - elapsedTime;
one example scenario: Profile of 'Work' is set from 9AM to 4:30PM, the service/app is executed at 2:02PM (EST), my toast message is executing constantly and is acting as a count down telling me how much time is left...in this case 2:28 and decreasing...ideally this should not display until the 2:28 is up...any ideas?
As per android doc:
With fixed-rate execution, the start time of each successive run of a task is scheduled without regard for when the previous run took place. This may result in a series of bunched-up runs (one launched immediately after another) if delays prevent the timer from starting tasks on time.
I think that could be the reason, may be you need to consider alternative 'fixed period'

Categories

Resources