1

I am trying to get a timer to run in a separate thread.

I have the following declaration before my onCreate function:

TimerTask scanTask;
Timer t = new Timer();

Then the following code within onCreate:

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        scanTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("timer test");
            }
        };

        t.schedule(scanTask, 0, 5000);

        CountDownTimer waitTimer;
        waitTimer = new CountDownTimer(20000,300) {
            @Override
            public void onTick(long l) {
            }
            @Override
            public void onFinish() {
                t.cancel();
                System.out.println("Timer stopped");
            }
        }.start();
    }
}; 

Thread periodic_scan = new Thread(runnable);
periodic_scan.start();

However, when I run the app, it crashes and gives me the error: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

I'm not sure I completely understand why this error is occurring. Is it something to do with the UI thread? Also, I'm not sure whether the way I've tried to implement this is correct. This is my first time trying to deal with threads in Android.

Osborne Cox
  • 466
  • 2
  • 7
  • 19

3 Answers3

1

you can use HandlerThread like

HandlerThread handlerThread = new HandlerThread("name");

handlerThread.start();

Handler threadHandler = new Handler(handlerThread.getLooper(),new Callback() {
    public boolean handleMessage(Message msg) {

    return true;  
 }
});
Leandro Hoffmann
  • 1,122
  • 1
  • 16
  • 30
laiwenjie
  • 81
  • 1
  • 4
1

I ended up changing the code a bit and decided to use a Thread class:

class TimerThread extends Thread {

    TimerTask scanTask;
    Timer t = new Timer();

    @Override
    public void run() {
        Looper.prepare();
        scanTask = new TimerTask() {
            public void run() {
                System.out.println("timer test");
            }
        };

        t.schedule(scanTask, 0, 5000);

        CountDownTimer waitTimer;
        waitTimer = new CountDownTimer(20000,300) {
            @Override
            public void onTick(long l) {

            }

            @Override
            public void onFinish() {
                t.cancel();
                System.out.println("Timer stopped");
            }
        }.start();

        Looper.loop();
    }
}

In onCreate I used the following:

new TimerThread().start();

The program now works without any errors, however the only problem now is that there is a noticeable 2-3 second lag when the program loads up before the UI renders to the screen.

I'm not sure why this is happening if the timer function I am using is running on a separate thread, unless I've missed something here...

Vasily Kabunov
  • 6,511
  • 13
  • 49
  • 53
Osborne Cox
  • 466
  • 2
  • 7
  • 19
  • OsborneCox : I am doing a very similar thing ,wherein I need to use a countdown timer inside a thread and was getting the error like yours.Using your code, did work.Can you pls tell the function of looper.Also,does this thread gets killed automatically once the countdown timers work is over? – Basher51 Dec 23 '14 at 07:09
  • 1
    @Basher51 There is a good explanation of Loopers here: http://stackoverflow.com/questions/7597742/what-is-the-purpose-of-looper-and-how-to-use-it – Osborne Cox Dec 24 '14 at 01:00
  • Creating your own Thread instances is more complicated than using **Executors** – IgorGanapolsky Jul 19 '18 at 13:10
0

If you create a handler (or any class you call creates a handler) it needs to be in a Thread that has a Looper on it, and has called Looper.prepare(). Either TimerTask or CountDownTimer is doing that. How to fix it depends on where you want the events to be posted to. If you want them on the UI thread, you'll have to create the handler on the UI thread. If you want them on this thread, then you need to call Looper.prepare and Looper.loop at some point.

The UI thread already has a looper (the framework starts it for you) so its always ok to make handlers there.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • I want the events posted on the new Thread. If this is the case, where should I be calling Looper.prepare() and Looper.loop()? – Osborne Cox Aug 06 '14 at 02:39
  • Prepare needs to be called before the handler is created. Loop should be the last statement of the thread, after its called the thread will only process messages and execution will never exit the loop function. – Gabe Sechan Aug 06 '14 at 03:27