1

I am trying to run a CountDownTimer inside a Thread, but it just won't work..

So in the MainActivitys onCreate I start it on Button click like that:

public void onClick(final View v) {
    Log.d("Main", "onClick");
    runOnUiThread(runner);
}

runner is an Instance of a class which implements Runnable:

private CountDownLatch doneSignal = new CountDownLatch(1);
@Override
public void run() {
    Log.d("WR", "run");
    this.countDown(20);
    Log.d("WR", "waiting");
    try {
        doneSignal.await();
    } catch (final InterruptedException ex) {
        Log.e("WR", ex.getMessage(), ex);
    }
    Log.d("WR", "waited");
}
private void countDown(int time) {
    final CountDownTimer timer = new CountDownTimer(time * 1000, 1000) {

        @Override
        public void onTick(final long millisUntilFinished) {
            Log.d("WR", "onTick");
        }

        @Override
        public void onFinish() {
            Log.d("WR", "onFinish");
            doneSignal.countDown();
        }
    };
    Log.d("WR", "starting");
    timer.start();
    Log.d("WR", "started");
}

With this code, the application just freezes after Logging onClick, run and starting. Changing runOnUiThread(runner) to new Thread(runner).start(); makes the application crash immediately after Logging onClick with no more output.

Some research said that the CountDownTimer needs to be run on UI-Thread due to the use of a Handler. But it just freezes.

When I remove the entire Thread stuff and just call runner.run(); in the Buttons onClick (also removing the implements Runnable in the runner Instance) I get following Log entries: onCLick, run, starting, started, waiting. But then nothing happens, as if the timer does not run, no call of the onTick method.

How can I fix my CountDownTimer?

Tobi
  • 924
  • 1
  • 10
  • 39
  • I don't know android, so I may be totally wrong here, but what's the point of calling runOnUiThread from inside an event handler? I'd have thought that the UI thread is what called your event handler in the first place. Why not just call `countDown(20)` directly from within your `onClick(v)` handler? – Solomon Slow Nov 02 '15 at 14:53
  • @jameslarge Yes, runOnUiThread is a result of me playing around. I am now starting a new Thread and the CountDownTimer in a new UiThread. I don't want to call countDown(20) in the onClick, this is all just the code to get to the specific problem without overload of anything else. Also calling await() and timer.start() in the same Thread (Ui-Thread) issued the dead-lock problem I had. – Tobi Nov 02 '15 at 15:05
  • If an Android `CountDownTimer` is anything like a `javax.swing.Timer`, then it's not a thing that "runs in a thread." It's a thing that you use to register a handler to be called at some future time(s) by the UI thread. The Android documentation is pretty vague about how `CountDownTimer` actually works, but I'd bet money that `timer.start()` does not actually _start_ anything. I'd bet that all it does is put a request into a time-ordered priority queue. – Solomon Slow Nov 02 '15 at 15:53
  • But the `CountDownLatch` was causing the problem, when calling `await()` the UI-Thread (or whatever you called it) is blocked. – Tobi Nov 02 '15 at 16:34
  • 1
    Sorry, I wasn't thinking about the CountDownLatch. I thought Blackbelt had answered your question about that. The problem is, you're calling `doneSignal.await()` in the UI thread (i.e., in an event handler). Don't do that. Don't call blocking functions from within an event handler. Your application can not respond to the next event (including the next Timer event) until the current event handler call returns. The `CountDownTimer` firing _is_ a UI event. It can not happen until that `run()` call returns, but the `run()` method is waiting for the timer to fire... – Solomon Slow Nov 02 '15 at 17:02
  • Yes, Blackbelt answered the question already for me. It is already working – Tobi Nov 02 '15 at 17:08

1 Answers1

3

CountDownTimer runs on The Ui Thread, and it has to run on the UI Thread, because internally it uses an Handler, which in turns neead a Looper. runOnUiThread(runner); whatever runner does, runs on the UI Thread.

private CountDownLatch doneSignal = new CountDownLatch(1);

calling await() on the UI Thread will block it, and since the countDown() runs on the same thread you practically dead-locked your app

Blackbelt
  • 156,034
  • 29
  • 297
  • 305
  • Thanks, I put my code in the `countDown` Method inside a new Runnable, called runOnUiThread while the rest is running in an extra Thread. And it is working now! – Tobi Nov 01 '15 at 14:51