Javad Noori
Javad Noori

Reputation: 31

why countdown counter with thread show wrong value?

I don't know why this count down counter shows a random number at the end?
I mean that it sometimes shows 60:15, sometimes 60:07, so on this way

min=sec=0;
new Thread(new Runnable() {
    @Override
    public void run() {
        while (min < 60  && flagTime) {
            try {
                Thread.sleep(1);
                G.HANDLER.post(new Runnable() {
                    @Override
                    public void run() {
                        String preSec="";
                        String preMin="";
                        if (sec < 59) {
                            sec += 1;
                        }
                        if (sec < 10) {
                            preSec = "0";
                        } 
                        if (min < 10) {
                            preMin = "0";
                        }
                        score =preMin + min + ":"
                                + preSec + sec;
                        txt[elementNumber + 1].setText(score);
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}).start();

Please someone tell me why it works so weird?

Upvotes: 3

Views: 99

Answers (2)

scottt
scottt

Reputation: 8371

The likely reason that you're getting weird results in your TextView is that you're updating it from a thread that is not the main UI thread.

But you're making this harder than it needs to be. An easier approach would be to use a simple CountDownTimer object like this:

final long SECS_IN_1_MIN = 60;
final long MILLIS_IN_1_SEC = 1000;
final long MILLIS_IN_60_MINS = 3600000;

final TextView timer = (TextView) findViewById(R.id.timer);
new CountDownTimer(MILLIS_IN_60_MINS, MILLIS_IN_1_SEC) {
    public void onTick(long millisUntilFinished) {
        if (flagTime) {
            long secs = (MILLIS_IN_60_MINS - millisUntilFinished) / MILLIS_IN_1_SEC;
            timer.setText(String.format("%02d:%02d", secs / SECS_IN_1_MIN, secs % SECS_IN_1_MIN));

        } else {
            timer.setText("cancelled");
            cancel();
        }
    }

    public void onFinish() {
        timer.setText("time expired");
    }
}.start();

Edit: It uses a CountDownTimer to handle the timing, while using its millisUntilFinished value to calculate and display what appears to be an increasing seconds count. I threw in some symbolic names to make the code clearer and a String.format to handle single digit values in a more elegant fashion. Enjoy!

Upvotes: 0

MBH
MBH

Reputation: 16609

Timing in ALL OSes is NOT precise, unless you use a framework or tools that is already designed for this task. You can however work with Thread.Sleep with a reasonable uncertainty. But for "reasonable" and "precise" timing, it depends on the problem you are trying to solve.

In threads, sleep(1000) does not mean that the thread will sleep exactly 1 second, so that the thread will sleep less or more every time you run your app. that is why you get random results.

This has many things else to consider like the priority of the thread. so a better way to count down is to use other ways which is provided by android:

CountDownTimer

Timer

you may check on google and you will find many examples about how to use them.

those are more reliable and more precise.

hope this helps.

Upvotes: 1

Related Questions