Android - CountDownTimer in ListView flickers randomly - java

I am making listview with timers, each with different deadline depending on the database(similar to auction)
Time now = new Time();
now.setToNow();
now.normalize(true);
nowMillis = now.toMillis(true);
.
.
String endtime = a.get(position).get(TAG_ENDTIME);
Integer timeSecond = Integer.parseInt(endtime.substring(17, 19));
Integer timeMinute = Integer.parseInt(endtime.substring(14, 16));
Integer timeHour = Integer.parseInt(endtime.substring(11, 13));
Integer timeDay = Integer.parseInt(endtime.substring(0, 2));
Integer timeMonth = Integer.parseInt(endtime.substring(3, 5)) - 1;
Integer timeYear = Integer.parseInt(endtime.substring(6, 10));
Time future = new Time();
future.set(timeSecond, timeMinute, timeHour, timeDay, timeMonth, timeYear);
future.normalize(true);
long futureMillis = future.toMillis(true);
long interval = futureMillis - nowMillis;
new CountDownTimer(interval,1000)
{
#Override
public void onTick(long millisUntilFinished)
{
Long interval = millisUntilFinished;
int days = (int) ((millisUntilFinished / 1000) / 86400);
int hours = (int) (((millisUntilFinished / 1000) - (days * 86400)) / 3600);
int minutes = (int) (((millisUntilFinished / 1000) - (days * 86400) - (hours * 3600)) / 60);
int seconds = (int) ((millisUntilFinished / 1000) % 60);
String countdown = String.format("%dd %dh %dm %ds", days, hours, minutes, seconds);
holder.duration.setText(countdown);
}
#Override
public void onFinish()
{
// TODO Auto-generated method stub
holder.duration.setText(TimeUp);
}
}.start();
That code works almost perfectly when there is only one instance.
However the problem arise when there is several instance, around 4-5 timer running at the same time
Several/all the countdown will start to flicker, be it seconds, minutes, hours, or days.
e.g. one of my timer flicker between 27d 11h 54m 50s and 0d 23h 47m 0s
Since this occur on both on emulator and on my device, it seems to be my code's flaw, but I don't have a clue what could cause this.
I tried to change
holder.duration.setText(countdown) into holder.duration.setText(millisUntilFinished)
and the the countdown flickers between the desired duration and a huge, random number,
Please help.

You should use one TimerTask and put all your UI updates into that single timer instead running multiple CountDownTimers for essentially the same job since you're already doing all the math to determine when "time is up" for any particular item, you might just run one TimerTask and once a second have it update everything. CountDownTimer is useful for a single implementation count down because it does some built-in math, etc. You're redoing all that math, so you might as well use one instance of a regular TimerTask.
The implementation of CountDownTimer relays on scheduled delays in Handler messaging. A single countdown instance is unlikely to result in any bizarre behavior, but if you have several going that all supposed to "tick" when the system clock hits each second (the time in millis ends in "000" - once a second, and all at the same time), then those handlers will all try to fire simultaneously and inevitably fail.
If the UI or other process will likely delay some of these messages, even to the point where it will "skip ticks" to catch up. Also, that means that the next message delay could be only milliseconds from the next tick (i.e. if it's supposed to check every 1000 millis, but is delayed an additional 1990 millis, then it will skip a tick and also schedule the next message for 10 millis into the future.

Related

How to represent passing of time?

I'm creating a simple simulation of gas station as homework. The total duration of the simulation is the week. Filling cars is approximately 3 minutes depending on the type of fuel. Cars may be collected in a queue. Now the question. I know how to implement these methods, but have no idea how to simulate a period of time without methods like a Thread.sleep().
P.S. I'm using JavaFX framework for this task. Cars are represented as javafx.scene.shape.Rectangle and their movements through Tranlsate methods. Dispensers too.
The Thread.sleep() method accepts a millisecond value. Basically, you can run an update and then calculate how long you need to sleep until the next update.
You can measure real time elapsed with System.nanoTime(). Make sure your class implements Runnable. Inside the run method, stick a while loop which contains an update() method to update the cars. Get nano time at the start and end of the loop, subtracting the two which gives you elapsed time. Subtract the elapsed time from the time you want each update to take, then sleep the thread. I think that is really all you need.
Here is the code:
public void run() {
int updatesPerSecond = 5;
/* The target time is the time each update should take.
* You want the target time to be in milliseconds.
* so 5 updates a second is 1000/5 milliseconds. */
int targetTime = 1000 / updatesPerSecond;
long currentTime;
long lastTime = System.nanoTime();
long elapsedTime;
long sleepTime;
while (running) {
// get current time (in nanoseconds)
currentTime = System.nanoTime();
// get time elapsed since last update
elapsedTime = currentTime - lastTime;
lastTime = currentTime;
// run your update
update();
// compute the thread sleep time in milliseconds.
// elapsed time is converted to milliseconds.
sleepTime = targetTime - (elapsedTime / 1000000000);
// don't let sleepTime drop below 0
if (sleepTime < 0) {
sleepTime = 1;
}
// attempt to sleep
try {
Thread.sleep(sleepTime);
} catch(Exception e) {
e.printStackTrace();
}
}
}
Within JavaFX framework,
you can simply use PauseTransition to simulate periodic time elapsing. On end of every period update scene graph elements' states. If you are going to change some properties of some node and do various animations you may utilize other types of Transitions. For more fine grained control you can use Timeline with its KeyFrames.

Signal at a specific interval with a countdown timer

Right now I have a CountDownTimer that ticks like this:
MyTimer(60000, 1);
So it ticks down 60 seconds with an interval of 1ms.
I am signaling bpm's in my timer.
This is done by dividing every minute by a bpm-number:
public void onTick(long millisLeft) {
if (TimeUnit.MILLISECONDS.toSeconds(millisLeft) % (60 / bpm) == 0) {
doSignal();
}
}
This works great, but ONLY if the timer is set to interval 1000
MyTimer(60000, 1000);
That means it will tick once every second (every 1000ms). But I need it to tick at 1ms.
The problem with my condition is that if the timer ticks at an interval of 1ms. It will start the signal when supposed to - but repeat rapidly.
If interval is 1000ms and bpm is set to 20, it will beep every third second (60/20 == 3). If the interval is set to 1ms, it will start beeping every third second - and beep repeatedly through that second.
So somehow my condition is true within a larger span than I intended with 1ms ticker interval.
How do I design my condition so it will fire only once every (60 / bpm) seconds with the timer at an interval of 1ms?
TimeUnit.MILLISECONDS.toSeconds(millisLeft) returns 57 for all 57000 <= millisLeft <= 57999 so within that second you get 1000 doSignal calls (as 57 % (60/20) == 0). And the same goes on for 54, 51, ... . To avoid this you could use this expression instead millisLeft % (60000/20) == 0.

Formatting time properly from milliseconds

I am timing an event like this:
seconds = System.currentTimeMillis() / 1000;
// Something happens here
time = System.currentTimeMillis() / 1000 - seconds;
and then I have attempted to format it:
String Time = String.format("%d min, %d sec",
TimeUnit.MILLISECONDS.toMinutes(time),
TimeUnit.MILLISECONDS.toSeconds(time) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(time)));
and the results don't make any sense, the minutes are thousands but the seconds seem to be normal numbers. What is the proper way to format the time?
long milliseconds = System.currentTimeMillis()%1000;
long seconds = (System.currentTimeMillis()/1000)%60;
long minutes = (System.currentTimeMillis()/(60*1000))%60;
long hours = (System.currentTimeMillis()/(60*60*1000));
Leave out whatever parts you don't want and remove the modulus from the highest one you do.

Odd values with timepicker and SystemClock.elapsedRealtime();

I have a TimePicker in my app that can select the amount of time for playback of a song, im having issues with getting the time remaining to display properly with the CountDownTimerim using, everything is pretty much going on behind the scenes in milliseconds of course and i think im doing the conversion right but all i see on the screen is just completely wrong values.
When i just make a test CountDownTimer with 3600000(1hour) as first argument, everything works fine, but when i put timepicker to 0 and minute to 1 , like i want just 1 minute of playback , it displays 12 hours and what seems like random values in the minutes and seconds slots. tp.getCurrentHour(); returns zero when set to zero and tp.getCurrentMinute(); returns one as expected, seems like something is happening with this part, cant figure out what yet:
playtime = (hour * (60 * 60 * 1000)) + (min * (60 * 1000));
startime = SystemClock.elapsedRealtime();
Why is tv2.setText("totaltest "+startime+playtime); displaying a value of 6000046929803??? That is obviously wrong...
Here is the the rest of the code:
TimePicker tp =(TimePicker)findViewById(R.id.timePicker1);
public void onClick(View v) {
// TODO Auto-generated method stub
long hour = tp.getCurrentHour();
long min = tp.getCurrentMinute();
playtime = (hour * (60 * 60 * 1000)) + (min * (60 * 1000));
startime = SystemClock.elapsedRealtime();
tv2.setText("totaltest "+startime+playtime);
timer = new CountDownTimer(startime+playtime,1000){
#Override
public void onFinish() {
tv.setText("finished");
}
//#SuppressLint("ParserError")
#Override
public void onTick(long millisUntilFinished) {
String display = DateUtils.formatElapsedTime(millisUntilFinished/1000);
tv.setText(display);
}
}.start();
Try:
String display = DateUtils.formatElapsedTime(millisUntilFinished/1000);
That does the conversion for you.
and:
timer = new CountDownTimer(playtime,1000){
as CounterDownTimer is expecting the amount of milliseconds to run.

schedule management

Finally after some trial and errors I have managed to make it work as I wanted.
But now I would like your advice to make the code more readable and simple it seems a made a lot of unnecessary code to archive what I wanted.
What this basicly do is, if you turn on the server app at a time a schedule task should be running, it will start the task and let it run for the time left from when it should have started otherwise it will be schedule to run at the hour it is supposed to run.
So if the schedule time is 13:00:00 and should run for 120 minutes and you start the app at 13:30 it will run for 90 minutes. If you start it after that time, it will be normally schedule for the next day 13:00:00.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
long start_time = calendar.getTimeInMillis() - System.currentTimeMillis();
if (start_time < 0)
{
long minutes = (start_time*-1) / (60 * 1000);
if (minutes > 0 && minutes < 120)
{
runTimeLeft = 120 - minutes;
ThreadPoolManager.getInstance().schedule(new Runnable()
{
public void run()
{
myTask();
}
}, 0);
}
else
runTimeLeft = 0;
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour+24);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
start_time = calendar.getTimeInMillis() - System.currentTimeMillis();
}
ThreadPoolManager.getInstance().scheduleAtFixedRate(new Runnable()
{
public void run()
{
myTask();
}
}, start_time, 24 * 60 * 60 * 1000);
So my question here now is what could I improve on the above code ?
Instead of using java.util.Timer alone, try using it with TimerTask. There is a good article from IBM on this.
Have a look at this link: http://www.ibm.com/developerworks/java/library/j-schedule.html
The code is also shared and seems to work for trivial routine job.
Use this instead for your first method:
int interval = 24 * 60 * 60 * 1000; // might be long instead of int
ThreadPoolManager.getInstance().scheduleAtFixedRate(new Runnable()
{
public void run()
{
myTask();
}
}, interval, interval);
This will create a simple timer that will call myTask() in 24 hours, and then every 24 hours after.
Your other requirement is a little different, though. If I understand your description correctly, you basically want your app to always execute some task at 12:00 AM if it happens to be up and running. If you don't care about down-to-the-millisecond accuracy for this, you could achieve it very simply by starting a Timer with a one minute period and checking the current system time in each tick - when you hit 12:00 AM run your daily task.
A fancier way would involve interacting with the OS such that it makes callbacks to your application at pre-scheduled times (possibly even starting your app if necessary), but this kind of thing is OS/platform specific (which you didn't specify).
Update: I know nothing about Linux, but it looks like a cron job is what you're looking for. See this question:
Running a scheduled task written in java on a linux server

Categories