43

I want to run some Runnable in a background thread. I want to use Handler because it's convenient for delays. What I mean is

handler.post(runnable, delay);

Where runnable should be run in background Thread. Is it possible to create such Handler? Is there a "background" Looper somewhere or how can I create it?

P.S. I know how to do it with a custom class extends Thread but it requires a little more coding effort than doing it the handler way. So please don't post other solutions or something like

handler.post(new Runnable() {
    @Override
    public void run() {
        new Thread() {
            @Override
            public void run() {
                //action
            }
        }.start();
    }
});

I just wander if Handler can do it the "clean" way.

Yaroslav Mytkalyk
  • 16,950
  • 10
  • 72
  • 99
  • You cannot run from background thread other thread. You can do this only from main thread. So if you want to run thread you can use: getActivity().runOnUiThread(new Runnable() { .... here you create new handler. – Dariusz Mazur Sep 09 '13 at 09:04
  • @daro2189 I want to run a background thread from main thread, but delayed. I see that Handler can accept Looper from any thread which has it. I just can't figure if it's possible to create a Looper in background thread. – Yaroslav Mytkalyk Sep 09 '13 at 09:08

5 Answers5

85

You can simply do this:

private Handler mHandler;

private HandlerThread mHandlerThread;

public void startHandlerThread(){
    mHandlerThread = new HandlerThread("HandlerThread");
    mHandlerThread.start();
    mHandler = new Handler(mHandlerThread.getLooper());
}

Then invoke with:

mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
          // Your task goes here
        }
    },1000);
Ananth
  • 2,597
  • 1
  • 29
  • 39
Himanshu Khandelwal
  • 5,341
  • 1
  • 17
  • 7
10

You can try something like this

    private void createHandler() {
        Thread thread = new Thread() {
            public void run() {
                Looper.prepare();

                final Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                       // Do Work
                        handler.removeCallbacks(this);
                        Looper.myLooper().quit();
                   }
                }, 2000);

                Looper.loop();
            }
        };
        thread.start();
    }
Paul Lammertsma
  • 37,593
  • 16
  • 136
  • 187
Ayman Mahgoub
  • 4,152
  • 1
  • 30
  • 27
5

You can set up a Looper in a background thread using Looper.prepare() and Looper.loop.

Yuichi Araki
  • 3,438
  • 1
  • 19
  • 24
  • That seems what I wanted. I was looking in the same doc running through methods but somehow I missed the example in the heading of the doc xD. – Yaroslav Mytkalyk Sep 09 '13 at 09:19
  • Good Article about [Loopers and Handlers] http://mindtherobot.com/blog/159/android-guts-intro-to-loopers-and-handlers/ – StepanM May 26 '14 at 15:24
0

Not clear what you mean by Handler.

It sounds like you need a thread that is fed processes to perform by a queue. You would probably benefit from investigating Executors here but here's a simple two-thread pair that communicate through a queue.

public class TwoThreads {
  public static void main(String args[]) throws InterruptedException {
    System.out.println("TwoThreads:Test");
    new TwoThreads().test();
  }
  // The end of the list.
  private static final Integer End = -1;

  static class Producer implements Runnable {
    final Queue<Integer> queue;

    public Producer(Queue<Integer> queue) {
      this.queue = queue;
    }

    @Override
    public void run() {
      try {
        for (int i = 0; i < 1000; i++) {
          queue.add(i);
          Thread.sleep(1);
        }
        // Finish the queue.
        queue.add(End);
      } catch (InterruptedException ex) {
        // Just exit.
      }
    }
  }

  static class Consumer implements Runnable {
    final Queue<Integer> queue;

    public Consumer(Queue<Integer> queue) {
      this.queue = queue;
    }

    @Override
    public void run() {
      boolean ended = false;
      while (!ended) {
        Integer i = queue.poll();
        if (i != null) {
          ended = i == End;
          System.out.println(i);
        }
      }
    }
  }

  public void test() throws InterruptedException {
    Queue<Integer> queue = new LinkedBlockingQueue<>();
    Thread pt = new Thread(new Producer(queue));
    Thread ct = new Thread(new Consumer(queue));
    // Start it all going.
    pt.start();
    ct.start();
    // Wait for it to finish.
    pt.join();
    ct.join();
  }
}
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • Thanks for the answer. Executors don't fit since there is only single thread that must be started with a delay, but cancelled if some condition happens before delay is ran out. Handler is perfect for this, but I want to run the Runnable in background, not in Main thread which Handler runs on by default. – Yaroslav Mytkalyk Sep 09 '13 at 09:11
0

I implemented simple way of running tasks on background thread in kotlin:

fun background(function: () -> Unit) = handler.post(function)

private val handler: Handler by lazy { Handler(handlerThread.looper) }

private val handlerThread: HandlerThread by lazy {
    HandlerThread("RenetikBackgroundThread").apply {
        setUncaughtExceptionHandler { _, e -> later { throw RuntimeException(e) } }
        start()
    }
}

The general idea is that tasks are simple to execute and running one after other sequentially and uncatched exceptions are propagated to main thread so they don't get lost. Function later is basically handler running on main thread.

So you can post tasks simply like this:

 background {
    some task to do in background...  
 }

some kode

 background {
    other task to do in background...  
    later {
        on main thread when all tasks are finished...
    }
 }
Renetik
  • 5,887
  • 1
  • 47
  • 66