I'm writing my first project in java, and I could use some help and experienced view. I'm trying to write stopWatch class, or something more like kitchen timer, which can provide this functionality:
- set hard start and end times,
- pause and start time from same place
- set if the time is decreasing or increasing
- move in Time up and down
- addTime (example: watch suppose to start at 00:00 end in 30:00 if we add 35 seconds stopWatch will end at 30:35);
- display time every second
I didn't find any good thread about this kind of stopWatch/kitchen timer here on stack overflow. My code is working, but I don't really have much of experience with OOD and java generally, so I'm expecting some flaws. It would be reasonable to use some pre-written classes instead? Or Date for time operation?
My code:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
// class for handle timer operation
public class stopWatch implements ActionListener {
public Timer timer; // timer object
private int startTime; // start time in seconds
private int endTime; // end time in seconds
private int actualTime; // actual time in seconds
private long memoryUnixTime; // actual time in Unix format
private boolean decrease; // is Timer decrease or incerease Time?
private int presize; // how often timer check for change of time
// construct
public stopWatch(int startTime, int endTime, boolean decrease, int presize){
this.startTime = startTime;
this.endTime = endTime;
this.decrease = decrease;
this.presize = presize;
this.actualTime = startTime;
}
// moving in Time UP
public void moveTimeUp (int seconds){
if(inScope("up",seconds))
actualTime += seconds;
}
// moving in Time DOWN
public void moveTimeDown (int seconds){
if(inScope("down",seconds))
actualTime -= seconds;
}
// is added time still inScope
private boolean inScope(String direction,int seconds){
boolean inScopeP;
switch(direction){
case "up":
inScopeP = ((this.actualTime + seconds) <= this.endTime);
break;
case "down":
inScopeP = ((this.actualTime - seconds) >= this.startTime);
break;
default:
inScopeP = false;
break;
}
return inScopeP;
}
// addTime - this option will be used only if we use increasing timer
public void addTime(int seconds){
if(this.decrease == false)
this.endTime += seconds;
}
// run stopwatch
public void run(){
System.out.println("start");
this.timer = new Timer(this.presize, this);
this.timer.setRepeats(true);
this.timer.start();
}
//stop stopwatch
public void pause(){
this.timer.stop();
this.timer = null;
}
// end of counting
public void end(){
System.out.println("END");
this.pause();
}
// event listener, handle change time
#Override
public void actionPerformed(ActionEvent e) {
// If the timer caused this event.
if (e.getSource().equals(timer)) {
long currentTime = System.currentTimeMillis();
// If time had change we decrease or increase time and print it out
if(changeTimeP(currentTime)){
// if time`s up we end the counting
if(this.actualTime == this.endTime){
this.end();
// else we do the math increase
} else{
this.memoryUnixTime = currentTime/1000;
if(decrease == true)
{
this.actualTime--;
} else {
this.actualTime++;
}
// println into console for testing purposes
int min = this.actualTime / 60;
int sec = this.actualTime % 60;
System.out.println(min+":"+sec);
}
}
}
}
// did time changed? (in matter of one second)
private boolean changeTimeP(long currentTime){
if(this.memoryUnixTime != (currentTime/1000L))
return true;
else return false;
}
}
Peter
Related
The CountDownTimer default Constructor takes the values millisInFuture and countDownInterval.
If the user stops the timer, changes his settings to a different millisInFuture length, how would I go about changing the millisInFuture value without creating a new CountDownTimer object?
I've tried making a getMillisInFuture method in the override CountDownTimer class to no avail.
Would I have to override the onStart method, or what?
This class will not let you do much by itself.
You can create a class that contains a CountDownTimer timer field and a method update(time, tick) that hides the implementation. You would still need to call timer.cancel() and create a new CountDownTimer with the new values. Either that, or create your countdown timer from scratch using a Handler and postDelayed(...)
Take a look at an example of the second approach in my answer here
I needed it too, here's the code
public class DynamicCountdownTimer {
private CountDownTimer timer = null;
private double negativeBias = 0.00;
private double addingBias = 0.00;
private int minutes = 0;
private int ticks = 0;
private boolean supressFinish = false;
public DynamicCountdownTimer(int minutes, int ticks){
setTimer(minutes, ticks);
}
public void updateMinutes(int minutes){
if (timer != null){
this.supressFinish = true;
this.timer.cancel();
this.timer = null;
this.minutes = minutes;
this.addingBias = this.negativeBias + this.addingBias;
setTimer(this.minutes, this.ticks);
Start();
}
}
public void setTimer(int minutes, int ticks){
this.minutes = minutes;
this.ticks = ticks;
timer = new CountDownTimer((minutes * 60 * 1000), ticks) {
#Override
public void onTick(long l) {
negativeBias = (minutes * 60 * 1000) - l;
long calculatedTime = l - (long)addingBias;
if (calculatedTime <= 0){
onFinish();
}else{
callback.onTick(calculatedTime);
}
}
#Override
public void onFinish() {
if (!supressFinish){
callback.onFinish();
}
supressFinish = false;
}
};
}
public void Start(){
if (timer != null){
timer.start();
}
}
public void Cancel(){
if (timer != null){
timer.cancel();
}
}
public DynamicCountdownCallback callback = null;
public void setDynamicCountdownCallback(DynamicCountdownCallback c){
callback = c;
}
public interface DynamicCountdownCallback {
void onTick(long l);
void onFinish();
}
}
Here is how to use it:
DynamicCountdownTimer pCountDownTimer = null;
public void initializeTimer(int minutes){
pCountDownTimer = new DynamicCountdownTimer(minutes, 1000);
pCountDownTimer.setDynamicCountdownCallback(new DynamicCountdownTimer.DynamicCountdownCallback() {
#Override
public void onTick(long l) {
double progress = (double)( l) / (double)(minutes * 60 * 1000);
}
#Override
public void onFinish() {
// do something
}
});
pCountDownTimer.Start();
}
Then you can update it like this:
public void updateTimer(int minutes){
pCountDownTimer.updateMinutes(minutes);
}
After updating, the timer will simply carry on. It also carries over the already passed time.
This means, if the time was originally set to 30min and you update it to 45min after 10min, the remaining countdown time will be 35min.
It does it by recreating a new Timer when the update function is called. And at onTick, the already passed time (before the update) is calculated into the new progress.
You can change it to ms instead of min if you need it simply by replacing
(double)(minutes * 60 * 1000) -> ms
then
int minutes -> long ms
I am using a countdown timer for audio notification... and it's not accurate from the start...
using initial parameters
private final long startCountDown;
private final long intervalCountDown;
...
startCountDown = 180 * 1000; // 3 mns - to be set from Preferences later
intervalCountDown = 60 * 1000; // 1 mns - to be set from Preferences later
...
public void onTick(long millisUntilFinished) {
Log.d(TAG, "notify countDown: " + millisUntilFinished + " msecs");
}
countDownTimer = new SwimCountDownTimer(startCountDown,intervalCountDown);
....
public void startCountDown() {
Log.d(TAG, "start countDown for " + startCountDown + " msecs" );
countDownTimer.start();
}
I can see in the log that the initial countdown is correctly set to 180000 but the next one should be 120000 and it's set to 119945 !!!
04-27 14:50:42.146: I/SWIMMER(8670): notify countDown: 180000 msecs
04-27 14:51:42.206: I/SWIMMER(8670): notify countDown: 119945 msecs
This is quite annoying as the audio notifier is expecting to say only '2 minutes" and not "1 minute and fifty nine seconds" ...; why the interval is not right ... ?
I can tricj it in setting myself the text to speech string ... but is there any way to get correct data ?
thanks for suggestions
I know it's an old question- but I've also encountered the problem, and thought I would share my solution.
Apperantly CountDownTimer isn't very accurate, so I've decided to implement a more percise countdown timer, using java.util.Timer:
public abstract class PreciseCountdown extends Timer {
private long totalTime, interval, delay;
private TimerTask task;
private long startTime = -1;
private boolean restart = false, wasCancelled = false, wasStarted = false;
public PreciseCountdown(long totalTime, long interval) {
this(totalTime, interval, 0);
}
public PreciseCountdown(long totalTime, long interval, long delay) {
super("PreciseCountdown", true);
this.delay = delay;
this.interval = interval;
this.totalTime = totalTime;
this.task = getTask(totalTime);
}
public void start() {
wasStarted = true;
this.scheduleAtFixedRate(task, delay, interval);
}
public void restart() {
if(!wasStarted) {
start();
}
else if(wasCancelled) {
wasCancelled = false;
this.task = getTask(totalTime);
start();
}
else{
this.restart = true;
}
}
public void stop() {
this.wasCancelled = true;
this.task.cancel();
}
// Call this when there's no further use for this timer
public void dispose(){
cancel();
purge();
}
private TimerTask getTask(final long totalTime) {
return new TimerTask() {
#Override
public void run() {
long timeLeft;
if (startTime < 0 || restart) {
startTime = scheduledExecutionTime();
timeLeft = totalTime;
restart = false;
} else {
timeLeft = totalTime - (scheduledExecutionTime() - startTime);
if (timeLeft <= 0) {
this.cancel();
startTime = -1;
onFinished();
return;
}
}
onTick(timeLeft);
}
};
}
public abstract void onTick(long timeLeft);
public abstract void onFinished();
}
Usage example would be:
this.countDown = new PreciseCountdown(totalTime, interval, delay) {
#Override
public void onTick(long timeLeft) {
// update..
// note that this runs on a different thread, so to update any GUI components you need to use Activity.runOnUiThread()
}
#Override
public void onFinished() {
onTick(0); // when the timer finishes onTick isn't called
// count down is finished
}
};
to start the countdown, simply call countDown.start().
countDown.stop() stops the countDown, which could be restarted using countDown.restart().
Hope this is any help for anyone in the future.
This is an extension on what Noam Gal posted. I added extra functionality where you can pause and resume the timer. This was very helpful in my case.
public abstract class PreciseCountdownTimer extends Timer {
private long totalTime, interval, delay;
private TimerTask task;
private long startTime = -1;
private long timeLeft;
private boolean restart = false;
private boolean wasCancelled = false;
private boolean wasStarted = false;
public PreciseCountdownTimer(long totalTime, long interval) {
this(totalTime, interval, 0);
}
public PreciseCountdownTimer(long totalTime, long interval, long delay ) {
super("PreciseCountdownTimer", true);
this.delay = delay;
this.interval = interval;
this.totalTime = totalTime;
this.task = buildTask(totalTime);
}
private TimerTask buildTask(final long totalTime) {
return new TimerTask() {
#Override
public void run() {
if (startTime < 0 || restart) {
startTime = scheduledExecutionTime();
timeLeft = totalTime;
restart = false;
} else {
timeLeft = totalTime - (scheduledExecutionTime() - startTime);
if (timeLeft <= 0) {
this.cancel();
wasCancelled = true;
startTime = -1;
onFinished();
return;
}
}
onTick(timeLeft);
}
};
}
public void start() {
wasStarted = true;
this.scheduleAtFixedRate(task, delay, interval);
}
public void stop() {
this.wasCancelled = true;
this.task.cancel();
}
public void restart() {
if (!wasStarted) {
start();
} else if (wasCancelled) {
wasCancelled = false;
this.task = buildTask(totalTime);
start();
} else {
this.restart = true;
}
}
public void pause(){
wasCancelled = true;
this.task.cancel();
onPaused();
}
public void resume(){
wasCancelled = false;
this.task = buildTask(timeLeft);
this.startTime = - 1;
start();
onResumed();
}
// Call this when there's no further use for this timer
public void dispose() {
this.cancel();
this.purge();
}
public abstract void onTick(long timeLeft);
public abstract void onFinished();
public abstract void onPaused();
public abstract void onResumed();
}
Usage example would be almost exactly the same:
this.timer = new PreciseCountdownTimer(totalTime, interval, delay) {
#Override
public void onTick(long timeLeft) {
// note that this runs on a different thread, so to update any GUI components you need to use Activity.runOnUiThread()
}
#Override
public void onFinished() {
onTick(0); // when the timer finishes onTick isn't called
// count down is finished
}
#Override
public void onPaused() {
// runs after the timer has been paused
}
#Override
public void onResumed() {
// runs after the timer has been resumed
}
};
Enjoy and have fun :D
That's true and I observed the same behaviour (logging millisUntilFinished):
9999 // 1 ms lag
8997 // 3 ms lag
7995 // 5 ms lag
6993 // 7 ms lag
5991 // 9 ms lag
4987 // 13 ms lag
3985 // 15 ms lag
2979 // 21 ms lag
1975 // 25 ms lag
971 // 29 ms lag
The reason is that it's implementation doesn't take into account the time a message stays in thread's message queue and the time needed for synchronization.
I prepared the fixed version (repo, class source).
It prints the following sequence:
9999 // 1 ms lag
8999 // 1 ms lag
7999 // 1 ms lag
6997 // 3 ms lag
5997 // 3 ms lag
4998 // 2 ms lag
3997 // 3 ms lag
2998 // 2 ms lag
1997 // 3 ms lag
997 // 3 ms lag
Small lag is still here, but the most important thing is that it doesn't accumulate.
To install it add in your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Add the dependency:
dependencies {
implementation 'com.github.cardinalby:accurate-count-down-timer:1.0'
}
Instead of using millisUntilFinished, you can use a variable to hold the remaining time and in every onTick, minus the variable with the interval. In this way, remainingTime is always accurate.
private class MyTimer(
countDownTime: Long,
interval: Long
) : CountDownTimer(countDownTime, interval) {
private var remainingTime = countDownTime
override fun onFinish() {
}
override fun onTick(millisUntilFinished: Long) {
// consume remainingTime here and then minus interval
remainingTime -= interval
}
}
I have a fairly simple JavaFX GUI application which has an label that shows how much time is left until a certain action starts. To achieve this, I've created a DownloadTimer class as shown below:
public class DownloadTimer(){
private int minutes;
private int seconds;
private Timer innerTimer = new Timer();
private TimerTask innerTask;
private boolean isActive;
public DownloadTimer(int minutes, int seconds) {
if (seconds > 60) {
int minToAdd = seconds / 60;
this.minutes = minutes;
this.minutes += minToAdd;
this.seconds = seconds % 60;
} else {
this.minutes = minutes;
this.seconds = seconds;
}
}
public void start() {
innerTask = new TimerTask() {
#Override
public void run() {
isActive = true;
System.out.println(getTime());
if (seconds == 0 && minutes > 0){
minutes -= 1;
seconds = 59;
} else if (seconds == 0 && minutes == 0){
isActive = false;
innerTimer.cancel();
innerTimer.purge();
System.out.println("DownloadTimer DONE");
} else {
seconds -= 1;
}
}
};
innerTimer.scheduleAtFixedRate(innerTask, 0, 1000);
}
}
And then, I'm creating the DownloadTimer object and starting the countdown from my Main (JavaFX) class:
/*
code omitted for better readability
*/
downloadTimer = new DownloadTimer(0, 5);
// label gets the .getTime() value, which returns a formatted String like "00:05", "00:04", etc.
lblTimer.setText( downloadTimer.getTime() );
// start the countdown
downloadTimer.start();
// create a new timer which checks if the downloadTimer is still counting
final Timer timer = new Timer();
TimerTask timerTask = new TimerTask(){
#Override
public void run(){
if (downloadTimer.getIsActive() == false){
timer.cancel();
timer.purge();
System.out.println("GUI timer DONE");
} else {
// if it's still running, then continuously update the label's text
lblTimer.setText( downloadTimer.getTime() );
// this is where I get the error described below
}
}
};
// repeat after 1000ms
timer.scheduleAtFixedRate(timerTask, 0, 1000);
The problem I'm encountering with this is that I can't set the label text with lblTimer.setText( downloadTimer.getTime() ); from the Main class, and the error I'm getting is TimerThread.run() line: not available [local variables unavailable] as seen here.
I've read about ScheduledThreadPoolExecutor and Java Timer vs ExecutorService, but I'm curious if this can be done using two separate Timers and TimerTasks. Any help and/or tips would be greatly appreciated.
I'm surprised you're not seeing an exception. To update a label from a separate thread, one needs to schedule an update to be run in the FX thread:
Platform.runLater(new Runnable() {
public void run() {
lblTimer.setText(downloadTimer.getTime());
}
});
I am new to countdown timer so I have no idea about this issue. I tried many things but I didn't get what I expected.
This is my code for the timer. It is a class within a class as usual.
// TIMER
public class Timer extends CountDownTimer {
public Timer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
//getNgo(true, score, tries, secLeft);
}
#Override
public void onTick(long millisUntilFinished) {
//secLeft = millisUntilFinished;
int sec = (int) (millisUntilFinished / 1000);
sec = sec % 60;
int min = sec / 60;
tvTime.setTextColor(Color.WHITE);
if (sec <= 10) {
animScale(tvTime);
tvTime.setTextColor(Color.RED);
tvTime.setText("" + min + ":" + sec);
if (sec < 10) {
tvTime.setTextColor(Color.RED);
tvTime.setText("" + min + ":0" + sec);
}
} else {
tvTime.setText("" + min + ":" + sec);
}
}
}
So, I just wanted to know how to deduct 3 seconds (that will be 3000 ms) when I push the button and the timer that is displayed by the textview will go on ticking but the time has already been deducted. And where do I put the code. Thanks!
When I've had to do this with tasks scheduled to take place in a fixed time, I've:
Cancelled the original task.
Submitted a new one with the new time period.
I suspect that this is a more standard pattern than your use of Timer anyway.
e.g.:
private final Runnable task = new Runnable() { #Override public void run() { /* ... */ } };
private final ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor();
private final long initialSeconds = 3;
public void submitTask() {
stpe.schedule(task, initialSeconds, TimeUnit.Seconds());
}
public void subtractSeconds(long sec) {
if(stpe.remove(task)) {
stpe.schedule(task, Math.Max(initialSeconds - sec, 0), TimeUnit.Seconds);
}
}
You will need to figure out:
how to ensure task is only initially-submitted once and keep track of fixed variable
whether you need one fixed final task or that task to be changed
concurrency/multithreading issues if the task can be submitted more than once
I've implemented a simple countdown using one of the stackoverflow posts
// gets current time
long timeNow = System.currentTimeMillis();
/* timer holds the values of the current second the timer should display
* requiredTime is the start value that the countdown should start from
* startTime is the time when the application starts
*/
timer = requiredTime - (timeNow - startTime) / 1000;
if (timer >= 0)
timer.setText(String.valueOf(timer));
To subtract the timer, subtract requiredTime and it will work. Because you've changed the reference value.
// Override onClickListener and add the line
// to deduct 3 seconds
requiredTime -= 3;
You can't. You have to write your own CountDownTimer. Copy original code and add method
public synchronized void addTime(long millis) {
mStopTimeInFuture += millis;
}
Then set onClickListener to the button
bt.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
timer.addTime(-2000);
}
});
Here is full sample code
Below I have a thread that updates a 'clock' label once per second. Once the thread reaches 600 (10 mins) the timer stops. The thread seems to trail by approx five seconds every minute. So when val = 60, in actuality 65 seconds may have elapsed. I'm using midp so I dont think I can introduce any api's to help me with this task. How can I improve on the accuracy below class? I think whats slowing it down is the method convertValToTimerString, is there a better way of converting the current timer val to minutes:seconds format without using java formatter apis?
Thanks,
public class LabelTimerUpdaterThread implements Runnable{
public static int val = 0;
private int minuteValueInt = 0;
private int secondValueInt = 0;
private int tempSecondValueInt;
public boolean isRunning = true;
public LabelTimerUpdaterThread(){
}
public void run() {
while(isRunning){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
val += 1;
incrementTimer();
if(val == 600){
break;
}
}
}
private void incrementTimer(){
Screen.timerLabel.setText(convertValToTimerString(val));
}
private String convertValToTimerString(int val){
String minuteValString = "";
String secondValString = "";
if(val < 10){
minuteValString = "00";
secondValString = "0"+String.valueOf(val);
return minuteValString+":"+secondValString;
}
if(val < 60){
minuteValString = "00";
secondValString = String.valueOf(val);
return minuteValString+":"+secondValString;
}
if(val % 60 == 0){
++minuteValueInt;
}
if(minuteValueInt < 10){
minuteValString = "0"+String.valueOf(minuteValueInt);
int secondVal = val % 60;
if(secondVal < 10){
return minuteValString+":0"+String.valueOf(secondVal);
}
else {
return minuteValString+":"+String.valueOf(secondVal);
}
}
return "10:00";
}
public void stopThread(){
this.isRunning = false;
}
Ok, now I am receiving an IllegalStateException when I try to upedate my timer label -
Here is my code -
Here i am instantiating my label -
timerLabel = new CustomLabelField("00:00" , Field.FIELD_LEFT , Constants.SMALL_FONT , Color.BLACK, Bitmap.getBitmapResource("bg_clock_white.png"));
UpdateValTimer timer = new UpdateValTimer(th);
timer.startTimer();
This class creates the timer class and creates the class which will update the timer label.
public class UpdateValTimer {
private Timer timer;
private int val = 0;
private UpdateView uv;
private final CustomLabelField customLabelField;
public UpdateValTimer(CustomLabelField field) {
this.customLabelField = field;
}
public void startTimer(){
timer = new Timer();
uv = new UpdateView(customLabelField);
Thread t = new Thread(uv);
t.start();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
++val;
}
}, 1000, 1000);
}
}
This class updates the timer label -
public class UpdateView implements Runnable{
private int val = 0;
private int minuteValueInt = 0;
private final CustomLabelField timerLabel;
public UpdateView(CustomLabelField timerLabel) {
this.timerLabel = timerLabel;
}
public void run() {
while(true){
this.timerLabel.setText(convertValToTimerString(this.val));
}
}
private String convertValToTimerString(int val){
String minuteValString = "";
String secondValString = "";
if(val < 10){
minuteValString = "00";
secondValString = "0"+String.valueOf(val);
return minuteValString+":"+secondValString;
}
if(val < 60){
minuteValString = "00";
secondValString = String.valueOf(val);
return minuteValString+":"+secondValString;
}
if(val % 60 == 0){
++minuteValueInt;
}
if(minuteValueInt < 10){
minuteValString = "0"+String.valueOf(minuteValueInt);
int secondVal = val % 60;
if(secondVal < 10){
return minuteValString+":0"+String.valueOf(secondVal);
}
else {
return minuteValString+":"+String.valueOf(secondVal);
}
}
return "10:00";
}
}
Thanks for any help
After some initial testing this code seems to be working correctly.
Thanks for all your help everyone.
Any comments on what I could be doing better are welcome.
public class UpdateValTimer{
private int minuteValueInt = 0;
private Timer timer;
private int val = 0;
private UpdateView uv;
private CustomLabelField customLabelField;
public UpdateValTimer(CustomLabelField field) {
this.customLabelField = field;
}
public void startTimer(){
timer = new Timer();
uv = new UpdateView(customLabelField);
Thread t = new Thread(uv);
t.start();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
++val;
uv.setVal(convertValToTimerString(val));
}
}, 1000, 1000);
}
private String convertValToTimerString(int val){
String minuteValString = "";
String secondValString = "";
if(val < 10){
minuteValString = "00";
secondValString = "0"+String.valueOf(val);
return minuteValString+":"+secondValString;
}
if(val < 60){
minuteValString = "00";
secondValString = String.valueOf(val);
return minuteValString+":"+secondValString;
}
if(val % 60 == 0){
++minuteValueInt;
}
if(minuteValueInt < 10){
minuteValString = "0"+String.valueOf(minuteValueInt);
int secondVal = val % 60;
if(secondVal < 10){
return minuteValString+":0"+String.valueOf(secondVal);
}
else {
return minuteValString+":"+String.valueOf(secondVal);
}
}
return "10:00";
}
}
public class UpdateView implements Runnable{
private String timeElapsedCounter;
private final CustomLabelField timerLabel;
public UpdateView(CustomLabelField timerLabel) {
this.timerLabel = timerLabel;
}
public void setVal(String timeElapsedCounter){
this.timeElapsedCounter = timeElapsedCounter;
}
public void run() {
while(true){
synchronized(Application.getEventLock()){
timerLabel.setText(this.timeElapsedCounter);
}
}
}
}
timerLabel = new CustomLabelField("00:00" , Field.FIELD_LEFT , Constants.SMALL_FONT , Color.BLACK, Bitmap.getBitmapResource("bg_clock_white.png"));
UpdateValTimer timer = new UpdateValTimer(timerLabel);
timer.startTimer();
Thread.sleep(1000);
Will put the thread into the sleeping state for at least 1s and after that it gets back to ready-to-run state which doesn't guarantee it will run immediatelly, it is just "ready to be scheduled for running anytime in the future". It is up to the thread scheduler when it will run it. You may want for example to check the system time to really know how much time elapsed ...
Try using ScheduledExecutorService.scheduleAtFixedRate which will execute your task at fixed intervals, regardless of how long the previous task took to complete.
If you want a timer, suggest you use a Timer. Also suggest that if you want to maintain a clock, you not attempt to do this yourself, but instead sample the system clock. Perhaps what you want is to sample currentTimeMillis()
There are two things that might help... First of all, the function incrementTimer() calls convertValToTimerString(). As you mentioned, this will introduce some slowdown. It will not be much, but over time this delay is going to accumulate. You're staying within the current thread of execution. A solution would be to use a model-view-controller scheme. The model would be your "val" field. The view is the label. The controller would then be the thread that updates this field once every second. By separating the model updates from the code execution required for viewing them, the update thread can run undisturbed. Of course, you'll still need a way to regularly update the text on the label based on your model's value. A separate thread could take care of this.
So what we have is:
A model (in your case, simply one value)
A controller (non-interactive thread updating the model)
A view (label)
A thread that updates the view
For the controller, using a Timer would indeed be a better choice rather than using a Runnable that calls Thread.sleep(), like andersoj suggested. You'll need to implement TimerTask. There is a difference between scheduling at fixed delay and scheduling at fixed rate. A fixed rate is preferrable for a task such as yours, where average consistency is more important than regularity. Do mind that if you use a Timer, the above model-view-controller scheme I suggested is a bit overkill. You'll probably be capable of incorporating the label update into the TimerTask's run method. But only because it will occur fast enough. If your view update requires more time (as might be the case for a combination of fast updates with heavy drawing) the MVC pattern will provide the proper separation of concerns and keep things spiffy.